Просмотр исходного кода

移除史诗004信用额度支付功能代码

yourname 1 месяц назад
Родитель
Сommit
9c980543d2
21 измененных файлов с 0 добавлено и 2349 удалено
  1. 0 81
      packages/credit-balance-module-mt/package.json
  2. 0 130
      packages/credit-balance-module-mt/src/entities/credit-balance-log.mt.entity.ts
  3. 0 81
      packages/credit-balance-module-mt/src/entities/credit-balance.mt.entity.ts
  4. 0 2
      packages/credit-balance-module-mt/src/entities/index.ts
  5. 0 5
      packages/credit-balance-module-mt/src/index.ts
  6. 0 82
      packages/credit-balance-module-mt/src/routes/adjust-limit.mt.ts
  7. 0 93
      packages/credit-balance-module-mt/src/routes/checkout.mt.ts
  8. 0 114
      packages/credit-balance-module-mt/src/routes/get-balance-logs.mt.ts
  9. 0 99
      packages/credit-balance-module-mt/src/routes/get-balance.mt.ts
  10. 0 21
      packages/credit-balance-module-mt/src/routes/index.ts
  11. 0 91
      packages/credit-balance-module-mt/src/routes/payment.mt.ts
  12. 0 102
      packages/credit-balance-module-mt/src/routes/set-limit.mt.ts
  13. 0 187
      packages/credit-balance-module-mt/src/schemas/index.ts
  14. 0 405
      packages/credit-balance-module-mt/src/services/credit-balance.service.ts
  15. 0 1
      packages/credit-balance-module-mt/src/services/index.ts
  16. 0 2
      packages/credit-balance-module-mt/src/types/index.ts
  17. 0 309
      packages/credit-balance-module-mt/tests/integration/credit-balance-routes.integration.test.ts
  18. 0 452
      packages/credit-balance-module-mt/tests/unit/credit-balance.service.test.ts
  19. 0 55
      packages/credit-balance-module-mt/tests/utils/test-data-factory.ts
  20. 0 16
      packages/credit-balance-module-mt/tsconfig.json
  21. 0 21
      packages/credit-balance-module-mt/vitest.config.ts

+ 0 - 81
packages/credit-balance-module-mt/package.json

@@ -1,81 +0,0 @@
-{
-  "name": "@d8d/credit-balance-module-mt",
-  "version": "1.0.0",
-  "description": "多租户信用额度管理模块 - 提供用户信用额度管理和支付权限控制,支持租户数据隔离",
-  "type": "module",
-  "main": "src/index.ts",
-  "types": "src/index.ts",
-  "exports": {
-    ".": {
-      "types": "./src/index.ts",
-      "import": "./src/index.ts",
-      "require": "./src/index.ts"
-    },
-    "./services": {
-      "types": "./src/services/index.ts",
-      "import": "./src/services/index.ts",
-      "require": "./src/services/index.ts"
-    },
-    "./schemas": {
-      "types": "./src/schemas/index.ts",
-      "import": "./src/schemas/index.ts",
-      "require": "./src/schemas/index.ts"
-    },
-    "./routes": {
-      "types": "./src/routes/index.ts",
-      "import": "./src/routes/index.ts",
-      "require": "./src/routes/index.ts"
-    },
-    "./entities": {
-      "types": "./src/entities/index.ts",
-      "import": "./src/entities/index.ts",
-      "require": "./src/entities/index.ts"
-    }
-  },
-  "files": [
-    "src"
-  ],
-  "scripts": {
-    "build": "tsc",
-    "dev": "tsc --watch",
-    "test": "vitest run",
-    "test:watch": "vitest",
-    "test:integration": "vitest run tests/integration",
-    "test:coverage": "vitest run --coverage",
-    "lint": "eslint src --ext .ts,.tsx",
-    "typecheck": "tsc --noEmit"
-  },
-  "dependencies": {
-    "@d8d/shared-types": "workspace:*",
-    "@d8d/shared-utils": "workspace:*",
-    "@d8d/shared-crud": "workspace:*",
-    "@d8d/core-module-mt": "workspace:*",
-    "@hono/zod-openapi": "^1.0.2",
-    "typeorm": "^0.3.20",
-    "zod": "^4.1.12"
-  },
-  "devDependencies": {
-    "@types/node": "^22.10.2",
-    "typescript": "^5.8.3",
-    "vitest": "^3.2.4",
-    "@d8d/shared-test-util": "workspace:*",
-    "@typescript-eslint/eslint-plugin": "^8.18.1",
-    "@typescript-eslint/parser": "^8.18.1",
-    "eslint": "^9.17.0"
-  },
-  "peerDependencies": {
-    "hono": "^4.8.5"
-  },
-  "keywords": [
-    "credit",
-    "balance",
-    "payment",
-    "credit-limit",
-    "crud",
-    "api",
-    "multi-tenant",
-    "tenant-isolation"
-  ],
-  "author": "D8D Team",
-  "license": "MIT"
-}

+ 0 - 130
packages/credit-balance-module-mt/src/entities/credit-balance-log.mt.entity.ts

@@ -1,130 +0,0 @@
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, Index } from 'typeorm';
-
-export enum CreditBalanceChangeType {
-  SET_LIMIT = 'SET_LIMIT',
-  PAYMENT = 'PAYMENT',
-  CHECKOUT = 'CHECKOUT',
-  CANCEL_ORDER = 'CANCEL_ORDER',
-  REFUND = 'REFUND',
-  ADJUST = 'ADJUST'
-}
-
-@Entity('credit_balance_log_mt')
-@Index('idx_tenant_user', ['tenantId', 'userId'])
-export class CreditBalanceLogMt {
-  @PrimaryGeneratedColumn({ unsigned: true })
-  id!: number;
-
-  @Column({
-    name: 'tenant_id',
-    type: 'int',
-    unsigned: true,
-    nullable: false,
-    comment: '租户ID'
-  })
-  tenantId!: number;
-
-  @Column({
-    name: 'user_id',
-    type: 'int',
-    unsigned: true,
-    nullable: false,
-    comment: '用户ID'
-  })
-  userId!: number;
-
-  @Column({
-    name: 'change_type',
-    type: 'varchar',
-    length: 20,
-    nullable: false,
-    comment: '变更类型: SET_LIMIT(设置额度), PAYMENT(支付扣减), CHECKOUT(结账恢复), CANCEL_ORDER(取消订单恢复), REFUND(退款恢复), ADJUST(调整额度)'
-  })
-  changeType!: CreditBalanceChangeType;
-
-  @Column({
-    name: 'change_amount',
-    type: 'decimal',
-    precision: 10,
-    scale: 2,
-    nullable: false,
-    comment: '变更金额(正数表示增加额度,负数表示减少额度)'
-  })
-  changeAmount!: number;
-
-  @Column({
-    name: 'before_total',
-    type: 'decimal',
-    precision: 10,
-    scale: 2,
-    nullable: true,
-    comment: '变更前总额度'
-  })
-  beforeTotal!: number | null;
-
-  @Column({
-    name: 'after_total',
-    type: 'decimal',
-    precision: 10,
-    scale: 2,
-    nullable: true,
-    comment: '变更后总额度'
-  })
-  afterTotal!: number | null;
-
-  @Column({
-    name: 'before_used',
-    type: 'decimal',
-    precision: 10,
-    scale: 2,
-    nullable: true,
-    comment: '变更前已用额度'
-  })
-  beforeUsed!: number | null;
-
-  @Column({
-    name: 'after_used',
-    type: 'decimal',
-    precision: 10,
-    scale: 2,
-    nullable: true,
-    comment: '变更后已用额度'
-  })
-  afterUsed!: number | null;
-
-  @Column({
-    name: 'reference_id',
-    type: 'varchar',
-    length: 100,
-    nullable: true,
-    comment: '关联ID(订单号等)'
-  })
-  @Index('idx_reference')
-  referenceId!: string | null;
-
-  @Column({
-    name: 'remark',
-    type: 'varchar',
-    length: 500,
-    nullable: true,
-    comment: '备注'
-  })
-  remark!: string | null;
-
-  @Column({
-    name: 'operator_id',
-    type: 'int',
-    unsigned: true,
-    nullable: true,
-    comment: '操作人ID'
-  })
-  operatorId!: number | null;
-
-  @CreateDateColumn({
-    name: 'created_at',
-    type: 'timestamp',
-    comment: '创建时间'
-  })
-  @Index('idx_created')
-  createdAt!: Date;
-}

+ 0 - 81
packages/credit-balance-module-mt/src/entities/credit-balance.mt.entity.ts

@@ -1,81 +0,0 @@
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Index, Unique } from 'typeorm';
-
-@Entity('credit_balance_mt')
-@Unique('uk_tenant_user', ['tenantId', 'userId'])
-export class CreditBalanceMt {
-  @PrimaryGeneratedColumn({ unsigned: true })
-  id!: number;
-
-  @Column({
-    name: 'tenant_id',
-    type: 'int',
-    unsigned: true,
-    nullable: false,
-    comment: '租户ID'
-  })
-  @Index('idx_tenant_id')
-  tenantId!: number;
-
-  @Column({
-    name: 'user_id',
-    type: 'int',
-    unsigned: true,
-    nullable: false,
-    comment: '用户ID'
-  })
-  @Index('idx_user_id')
-  userId!: number;
-
-  @Column({
-    name: 'total_limit',
-    type: 'decimal',
-    precision: 10,
-    scale: 2,
-    default: 0.00,
-    comment: '总额度'
-  })
-  totalLimit!: number;
-
-  @Column({
-    name: 'used_amount',
-    type: 'decimal',
-    precision: 10,
-    scale: 2,
-    default: 0.00,
-    comment: '已用额度'
-  })
-  usedAmount!: number;
-
-  @Column({
-    name: 'available_amount',
-    type: 'decimal',
-    precision: 10,
-    scale: 2,
-    generatedType: 'STORED',
-    asExpression: 'total_limit - used_amount',
-    comment: '可用额度'
-  })
-  availableAmount!: number;
-
-  @Column({
-    name: 'is_enabled',
-    type: 'smallint',
-    default: 1,
-    comment: '是否启用(0:禁用,1:启用)'
-  })
-  isEnabled!: number;
-
-  @CreateDateColumn({
-    name: 'created_at',
-    type: 'timestamp',
-    comment: '创建时间'
-  })
-  createdAt!: Date;
-
-  @UpdateDateColumn({
-    name: 'updated_at',
-    type: 'timestamp',
-    comment: '更新时间'
-  })
-  updatedAt!: Date;
-}

+ 0 - 2
packages/credit-balance-module-mt/src/entities/index.ts

@@ -1,2 +0,0 @@
-export * from './credit-balance.mt.entity';
-export * from './credit-balance-log.mt.entity';

+ 0 - 5
packages/credit-balance-module-mt/src/index.ts

@@ -1,5 +0,0 @@
-export * from './entities';
-export * from './services';
-export * from './schemas';
-export * from './routes';
-export * from './types';

+ 0 - 82
packages/credit-balance-module-mt/src/routes/adjust-limit.mt.ts

@@ -1,82 +0,0 @@
-import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
-import { z } from '@hono/zod-openapi';
-import { authMiddleware } from '@d8d/core-module-mt/auth-module-mt/middleware';
-import { AppDataSource, ErrorSchema } from '@d8d/shared-utils';
-import { AuthContext } from '@d8d/shared-types';
-import { CreditBalanceService } from '../services';
-import { CreditBalanceSchema, AdjustLimitDto } from '../schemas';
-
-const adjustLimitRoute = createRoute({
-  method: 'post',
-  path: '/{userId}/adjust',
-  middleware: [authMiddleware],
-  request: {
-    params: z.object({
-      userId: z.string().openapi({
-        param: {
-          name: 'userId',
-          in: 'path'
-        },
-        description: '用户ID',
-        example: '1001'
-      })
-    }),
-    body: {
-      content: {
-        'application/json': {
-          schema: AdjustLimitDto
-        }
-      }
-    }
-  },
-  responses: {
-    200: {
-      description: '调整用户信用额度成功',
-      content: {
-        'application/json': {
-          schema: CreditBalanceSchema
-        }
-      }
-    },
-    400: {
-      description: '请求参数错误'
-    },
-    401: {
-      description: '认证失败'
-    },
-    403: {
-      description: '权限不足'
-    },
-    500: {
-      description: '服务器内部错误'
-    }
-  }
-});
-
-const adjustLimitRoutes = new OpenAPIHono<AuthContext>()
-  .openapi(adjustLimitRoute, async (c) => {
-    const user = c.get('user');
-    const userId = parseInt(c.req.param('userId'));
-    const data = c.req.valid('json');
-
-    try {
-      const service = new CreditBalanceService(AppDataSource);
-      const balance = await service.adjustLimit({
-        tenantId: user.tenantId,
-        userId,
-        adjustAmount: data.adjustAmount,
-        operatorId: data.operatorId,
-        remark: data.remark
-      });
-
-      return c.json(CreditBalanceSchema.parse(balance), 200);
-    } catch (error) {
-      console.error('调整用户信用额度失败:', error);
-      return c.json(
-        { code: 500, message: error instanceof Error ? error.message : '调整用户信用额度失败' },
-        500
-      );
-    }
-  });
-
-export default adjustLimitRoutes;

+ 0 - 93
packages/credit-balance-module-mt/src/routes/checkout.mt.ts

@@ -1,93 +0,0 @@
-import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
-import { authMiddleware } from '@d8d/core-module-mt/auth-module-mt/middleware';
-import { AppDataSource, ErrorSchema } from '@d8d/shared-utils';
-import { AuthContext } from '@d8d/shared-types';
-import { CreditBalanceService } from '../services';
-import { CreditBalanceChangeType } from '../entities';
-import { CreditBalanceSchema, CheckoutDto } from '../schemas';
-
-const checkoutRoute = createRoute({
-  method: 'post',
-  path: '/checkout',
-  middleware: [authMiddleware],
-  request: {
-    body: {
-      content: {
-        'application/json': {
-          schema: CheckoutDto
-        }
-      }
-    }
-  },
-  responses: {
-    200: {
-      description: '结账恢复额度成功',
-      content: {
-        'application/json': {
-          schema: CreditBalanceSchema
-        }
-      }
-    },
-    400: {
-      description: '请求参数错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    401: {
-      description: '认证失败',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    403: {
-      description: '权限不足',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    500: {
-      description: '服务器内部错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    }
-  }
-});
-
-const checkoutRoutes = new OpenAPIHono<AuthContext>()
-  .openapi(checkoutRoute, async (c) => {
-    const user = c.get('user');
-    const data = c.req.valid('json');
-
-    try {
-      const service = new CreditBalanceService(AppDataSource);
-      const balance = await service.restoreAmount({
-        tenantId: user.tenantId,
-        userId: data.userId,
-        amount: data.amount,
-        changeType: CreditBalanceChangeType.CHECKOUT,
-        referenceId: data.referenceId,
-        operatorId: data.operatorId,
-        remark: data.remark
-      });
-
-      return c.json(CreditBalanceSchema.parse(balance), 200);
-    } catch (error) {
-      console.error('结账恢复额度失败:', error);
-      return c.json(
-        { code: 500, message: error instanceof Error ? error.message : '结账恢复额度失败' },
-        500
-      );
-    }
-  });
-
-export default checkoutRoutes;

+ 0 - 114
packages/credit-balance-module-mt/src/routes/get-balance-logs.mt.ts

@@ -1,114 +0,0 @@
-import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
-import { z } from '@hono/zod-openapi';
-import { authMiddleware } from '@d8d/core-module-mt/auth-module-mt/middleware';
-import { AppDataSource, ErrorSchema } from '@d8d/shared-utils';
-import { AuthContext } from '@d8d/shared-types';
-import { CreditBalanceService } from '../services';
-import { CreditBalanceLogSchema, QueryBalanceLogsDto } from '../schemas';
-
-const getBalanceLogsRoute = createRoute({
-  method: 'get',
-  path: '/{userId}/logs',
-  middleware: [authMiddleware],
-  request: {
-    params: z.object({
-      userId: z.string().openapi({
-        param: {
-          name: 'userId',
-          in: 'path'
-        },
-        description: '用户ID',
-        example: '1001'
-      })
-    }),
-    query: QueryBalanceLogsDto
-  },
-  responses: {
-    200: {
-      description: '获取额度变更记录成功',
-      content: {
-        'application/json': {
-          schema: z.object({
-            data: z.array(CreditBalanceLogSchema),
-            pagination: z.object({
-              page: z.number(),
-              pageSize: z.number(),
-              total: z.number(),
-              totalPages: z.number()
-            })
-          })
-        }
-      }
-    },
-    400: {
-      description: '请求参数错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    401: {
-      description: '认证失败',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    403: {
-      description: '权限不足',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    500: {
-      description: '服务器内部错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    }
-  }
-});
-
-const getBalanceLogsRoutes = new OpenAPIHono<AuthContext>()
-  .openapi(getBalanceLogsRoute, async (c) => {
-    const user = c.get('user');
-    const userId = parseInt(c.req.param('userId'));
-    const query = c.req.valid('query');
-
-    try {
-      const service = new CreditBalanceService(AppDataSource);
-      const page = query.page || 1;
-      const pageSize = query.pageSize || 20;
-
-      const [logs, total] = await service.getBalanceLogs(
-        user.tenantId,
-        userId,
-        page,
-        pageSize
-      );
-
-      return c.json({
-        data: logs,
-        pagination: {
-          page,
-          pageSize,
-          total,
-          totalPages: Math.ceil(total / pageSize)
-        }
-      }, 200);
-    } catch (error) {
-      console.error('获取额度变更记录失败:', error);
-      return c.json(
-        { code: 500, message: error instanceof Error ? error.message : '获取额度变更记录失败' },
-        500
-      );
-    }
-  });
-
-export default getBalanceLogsRoutes;

+ 0 - 99
packages/credit-balance-module-mt/src/routes/get-balance.mt.ts

@@ -1,99 +0,0 @@
-import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
-import { z } from '@hono/zod-openapi';
-import { authMiddleware } from '@d8d/core-module-mt/auth-module-mt/middleware';
-import { AppDataSource, ErrorSchema } from '@d8d/shared-utils';
-import { AuthContext } from '@d8d/shared-types';
-import { CreditBalanceService } from '../services';
-import { CreditBalanceSchema } from '../schemas';
-
-const getBalanceRoute = createRoute({
-  method: 'get',
-  path: '/{userId}',
-  middleware: [authMiddleware],
-  request: {
-    params: z.object({
-      userId: z.string().openapi({
-        param: {
-          name: 'userId',
-          in: 'path'
-        },
-        description: '用户ID',
-        example: '1001'
-      })
-    })
-  },
-  responses: {
-    200: {
-      description: '获取用户信用额度成功',
-      content: {
-        'application/json': {
-          schema: CreditBalanceSchema
-        }
-      }
-    },
-    400: {
-      description: '请求参数错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    401: {
-      description: '认证失败',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    403: {
-      description: '权限不足',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    404: {
-      description: '用户信用额度记录不存在',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    500: {
-      description: '服务器内部错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    }
-  }
-});
-
-const getBalanceRoutes = new OpenAPIHono<AuthContext>()
-  .openapi(getBalanceRoute, async (c) => {
-    const user = c.get('user');
-    const userId = parseInt(c.req.param('userId'));
-
-    try {
-      const service = new CreditBalanceService(AppDataSource);
-      const balance = await service.getBalance(user.tenantId, userId);
-      if (!balance) {
-        return c.json({ code: 404, message: '用户信用额度记录不存在' }, 404);
-      }
-
-      return c.json(CreditBalanceSchema.parse(balance), 200);
-    } catch (error) {
-      console.error('获取用户信用额度失败:', error);
-      return c.json(
-        { code: 500, message: error instanceof Error ? error.message : '获取用户信用额度失败' },
-        500
-      );
-    }
-  });
-
-export default getBalanceRoutes;

+ 0 - 21
packages/credit-balance-module-mt/src/routes/index.ts

@@ -1,21 +0,0 @@
-// 导出所有多租户信用额度路由
-import { OpenAPIHono } from '@hono/zod-openapi';
-import { AuthContext } from '@d8d/shared-types';
-
-import getBalanceRoutes from './get-balance.mt';
-import setLimitRoutes from './set-limit.mt';
-import adjustLimitRoutes from './adjust-limit.mt';
-import getBalanceLogsRoutes from './get-balance-logs.mt';
-import paymentRoutes from './payment.mt';
-import checkoutRoutes from './checkout.mt';
-
-// 聚合所有信用额度路由
-const creditBalanceRoutes = new OpenAPIHono<AuthContext>()
-  .route('/', getBalanceRoutes)
-  .route('/', setLimitRoutes)
-  .route('/', adjustLimitRoutes)
-  .route('/', getBalanceLogsRoutes)
-  .route('/', paymentRoutes)
-  .route('/', checkoutRoutes);
-
-export default creditBalanceRoutes;

+ 0 - 91
packages/credit-balance-module-mt/src/routes/payment.mt.ts

@@ -1,91 +0,0 @@
-import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
-import { authMiddleware } from '@d8d/core-module-mt/auth-module-mt/middleware';
-import { AppDataSource, ErrorSchema } from '@d8d/shared-utils';
-import { AuthContext } from '@d8d/shared-types';
-import { CreditBalanceService } from '../services';
-import { CreditBalanceSchema, PaymentDto } from '../schemas';
-
-const paymentRoute = createRoute({
-  method: 'post',
-  path: '/payment',
-  middleware: [authMiddleware],
-  request: {
-    body: {
-      content: {
-        'application/json': {
-          schema: PaymentDto
-        }
-      }
-    }
-  },
-  responses: {
-    200: {
-      description: '额度支付成功',
-      content: {
-        'application/json': {
-          schema: CreditBalanceSchema
-        }
-      }
-    },
-    400: {
-      description: '请求参数错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    401: {
-      description: '认证失败',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    403: {
-      description: '权限不足',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    500: {
-      description: '服务器内部错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    }
-  }
-});
-
-const paymentRoutes = new OpenAPIHono<AuthContext>()
-  .openapi(paymentRoute, async (c) => {
-    const user = c.get('user');
-    const data = c.req.valid('json');
-
-    try {
-      const service = new CreditBalanceService(AppDataSource);
-      const balance = await service.deductAmount({
-        tenantId: user.tenantId,
-        userId: user.id,
-        amount: data.amount,
-        referenceId: data.referenceId,
-        operatorId: data.operatorId,
-        remark: data.remark
-      });
-
-      return c.json(CreditBalanceSchema.parse(balance), 200);
-    } catch (error) {
-      console.error('额度支付失败:', error);
-      return c.json(
-        { code: 500, message: error instanceof Error ? error.message : '额度支付失败' },
-        500
-      );
-    }
-  });
-
-export default paymentRoutes;

+ 0 - 102
packages/credit-balance-module-mt/src/routes/set-limit.mt.ts

@@ -1,102 +0,0 @@
-import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
-import { z } from '@hono/zod-openapi';
-import { authMiddleware } from '@d8d/core-module-mt/auth-module-mt/middleware';
-import { AppDataSource, ErrorSchema } from '@d8d/shared-utils';
-import { AuthContext } from '@d8d/shared-types';
-import { CreditBalanceService } from '../services';
-import { CreditBalanceSchema, SetLimitDto } from '../schemas';
-
-const setLimitRoute = createRoute({
-  method: 'put',
-  path: '/{userId}',
-  middleware: [authMiddleware],
-  request: {
-    params: z.object({
-      userId: z.string().openapi({
-        param: {
-          name: 'userId',
-          in: 'path'
-        },
-        description: '用户ID',
-        example: '1001'
-      })
-    }),
-    body: {
-      content: {
-        'application/json': {
-          schema: SetLimitDto
-        }
-      }
-    }
-  },
-  responses: {
-    200: {
-      description: '设置用户信用额度成功',
-      content: {
-        'application/json': {
-          schema: CreditBalanceSchema
-        }
-      }
-    },
-    400: {
-      description: '请求参数错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    401: {
-      description: '认证失败',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    403: {
-      description: '权限不足',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    },
-    500: {
-      description: '服务器内部错误',
-      content: {
-        'application/json': {
-          schema: ErrorSchema
-        }
-      }
-    }
-  }
-});
-
-const setLimitRoutes = new OpenAPIHono<AuthContext>()
-  .openapi(setLimitRoute, async (c) => {
-    const user = c.get('user');
-    const userId = parseInt(c.req.param('userId'));
-    const data = c.req.valid('json');
-
-    try {
-      const service = new CreditBalanceService(AppDataSource);
-      const balance = await service.setLimit({
-        tenantId: user.tenantId,
-        userId,
-        totalLimit: data.totalLimit,
-        operatorId: data.operatorId,
-        remark: data.remark
-      });
-
-      return c.json(CreditBalanceSchema.parse(balance), 200);
-    } catch (error) {
-      console.error('设置用户信用额度失败:', error);
-      return c.json(
-        { code: 500, message: error instanceof Error ? error.message : '设置用户信用额度失败' },
-        500
-      );
-    }
-  });
-
-export default setLimitRoutes;

+ 0 - 187
packages/credit-balance-module-mt/src/schemas/index.ts

@@ -1,187 +0,0 @@
-import { z } from '@hono/zod-openapi';
-import { CreditBalanceChangeType } from '../entities';
-import { ErrorSchema } from '@d8d/shared-utils';
-
-// 信用额度实体Schema
-export const CreditBalanceSchema = z.object({
-  id: z.number().int().positive().openapi({
-    description: '额度记录ID',
-    example: 1
-  }),
-  tenantId: z.number().int().positive().openapi({
-    description: '租户ID',
-    example: 1
-  }),
-  userId: z.number().int().positive().openapi({
-    description: '用户ID',
-    example: 1001
-  }),
-  totalLimit: z.coerce.number().openapi({
-    description: '总额度',
-    example: 10000.00
-  }),
-  usedAmount: z.coerce.number().openapi({
-    description: '已用额度',
-    example: 500.00
-  }),
-  availableAmount: z.coerce.number().openapi({
-    description: '可用额度',
-    example: 9500.00
-  }),
-  isEnabled: z.number().int().min(0).max(1).openapi({
-    description: '是否启用(0:禁用,1:启用)',
-    example: 1
-  }),
-  createdAt: z.coerce.date().openapi({
-    description: '创建时间',
-    example: '2024-01-01T00:00:00Z'
-  }),
-  updatedAt: z.coerce.date().openapi({
-    description: '更新时间',
-    example: '2024-01-01T00:00:00Z'
-  })
-});
-
-// 额度变更记录实体Schema
-export const CreditBalanceLogSchema = z.object({
-  id: z.number().int().positive().openapi({
-    description: '变更记录ID',
-    example: 1
-  }),
-  tenantId: z.number().int().positive().openapi({
-    description: '租户ID',
-    example: 1
-  }),
-  userId: z.number().int().positive().openapi({
-    description: '用户ID',
-    example: 1001
-  }),
-  changeType: z.nativeEnum(CreditBalanceChangeType).openapi({
-    description: '变更类型',
-    example: CreditBalanceChangeType.PAYMENT
-  }),
-  changeAmount: z.coerce.number().openapi({
-    description: '变更金额(正数表示增加额度,负数表示减少额度)',
-    example: -500.00
-  }),
-  beforeTotal: z.coerce.number().nullable().openapi({
-    description: '变更前总额度',
-    example: 10000.00
-  }),
-  afterTotal: z.coerce.number().nullable().openapi({
-    description: '变更后总额度',
-    example: 10000.00
-  }),
-  beforeUsed: z.coerce.number().nullable().openapi({
-    description: '变更前已用额度',
-    example: 0.00
-  }),
-  afterUsed: z.coerce.number().nullable().openapi({
-    description: '变更后已用额度',
-    example: 500.00
-  }),
-  referenceId: z.string().nullable().openapi({
-    description: '关联ID(订单号等)',
-    example: 'ORD202412010001'
-  }),
-  remark: z.string().nullable().openapi({
-    description: '备注',
-    example: '订单支付扣减额度'
-  }),
-  operatorId: z.number().int().positive().nullable().openapi({
-    description: '操作人ID',
-    example: 1
-  }),
-  createdAt: z.coerce.date().openapi({
-    description: '创建时间',
-    example: '2024-01-01T00:00:00Z'
-  })
-});
-
-// 设置额度DTO
-export const SetLimitDto = z.object({
-  totalLimit: z.number().min(0).openapi({
-    description: '总额度',
-    example: 10000.00
-  }),
-  operatorId: z.number().int().positive().optional().openapi({
-    description: '操作人ID',
-    example: 1
-  }),
-  remark: z.string().max(500).optional().openapi({
-    description: '备注',
-    example: '初始化用户信用额度'
-  })
-});
-
-// 调整额度DTO
-export const AdjustLimitDto = z.object({
-  adjustAmount: z.number().openapi({
-    description: '调整金额(正数表示增加额度,负数表示减少额度)',
-    example: 1000.00
-  }),
-  operatorId: z.number().int().positive().optional().openapi({
-    description: '操作人ID',
-    example: 1
-  }),
-  remark: z.string().max(500).optional().openapi({
-    description: '备注',
-    example: '根据用户等级调整额度'
-  })
-});
-
-// 额度支付DTO(用户操作)
-export const PaymentDto = z.object({
-  amount: z.number().positive().openapi({
-    description: '支付金额',
-    example: 500.00
-  }),
-  referenceId: z.string().max(100).optional().openapi({
-    description: '关联ID(订单号等)',
-    example: 'ORD202412010001'
-  }),
-  operatorId: z.number().int().positive().optional().openapi({
-    description: '操作人ID',
-    example: 1
-  }),
-  remark: z.string().max(500).optional().openapi({
-    description: '备注',
-    example: '订单支付扣减额度'
-  })
-});
-
-// 结账恢复额度DTO(管理员操作)
-export const CheckoutDto = z.object({
-  userId: z.number().int().positive().openapi({
-    description: '用户ID',
-    example: 1001
-  }),
-  amount: z.number().positive().openapi({
-    description: '恢复金额',
-    example: 500.00
-  }),
-  referenceId: z.string().max(100).optional().openapi({
-    description: '关联ID(订单号等)',
-    example: 'ORD202412010001'
-  }),
-  operatorId: z.number().int().positive().optional().openapi({
-    description: '操作人ID',
-    example: 1
-  }),
-  remark: z.string().max(500).optional().openapi({
-    description: '备注',
-    example: '结账恢复额度'
-  })
-});
-
-// 查询额度变更记录DTO
-export const QueryBalanceLogsDto = z.object({
-  page: z.coerce.number().int().positive().default(1).optional().openapi({
-    description: '页码',
-    example: 1
-  }),
-  pageSize: z.coerce.number().int().positive().max(100).default(20).optional().openapi({
-    description: '每页数量',
-    example: 20
-  })
-});

+ 0 - 405
packages/credit-balance-module-mt/src/services/credit-balance.service.ts

@@ -1,405 +0,0 @@
-import { DataSource, EntityManager, Repository } from 'typeorm';
-import { CreditBalanceMt, CreditBalanceLogMt, CreditBalanceChangeType } from '../entities';
-
-export interface SetLimitParams {
-  tenantId: number;
-  userId: number;
-  totalLimit: number;
-  operatorId?: number;
-  remark?: string;
-}
-
-export interface AdjustLimitParams {
-  tenantId: number;
-  userId: number;
-  adjustAmount: number;
-  operatorId?: number;
-  remark?: string;
-}
-
-export interface DeductAmountParams {
-  tenantId: number;
-  userId: number;
-  amount: number;
-  referenceId?: string;
-  operatorId?: number;
-  remark?: string;
-}
-
-export interface RestoreAmountParams {
-  tenantId: number;
-  userId: number;
-  amount: number;
-  changeType: CreditBalanceChangeType;
-  referenceId?: string;
-  operatorId?: number;
-  remark?: string;
-}
-
-export class CreditBalanceService {
-  private creditBalanceRepository: Repository<CreditBalanceMt>;
-  private creditBalanceLogRepository: Repository<CreditBalanceLogMt>;
-
-  constructor(private dataSource: DataSource) {
-    this.creditBalanceRepository = dataSource.getRepository(CreditBalanceMt);
-    this.creditBalanceLogRepository = dataSource.getRepository(CreditBalanceLogMt);
-  }
-
-  /**
-   * 设置用户信用额度
-   */
-  async setLimit(params: SetLimitParams): Promise<CreditBalanceMt> {
-    const { tenantId, userId, totalLimit, operatorId, remark } = params;
-
-    return await this.dataSource.transaction(async (manager) => {
-      const repository = manager.getRepository(CreditBalanceMt);
-      const logRepository = manager.getRepository(CreditBalanceLogMt);
-
-      // 查找或创建信用额度记录
-      let creditBalance = await repository.findOne({
-        where: { tenantId, userId }
-      });
-
-      const beforeTotal = creditBalance ? Number(creditBalance.totalLimit) : 0;
-      const beforeUsed = creditBalance ? Number(creditBalance.usedAmount) : 0;
-
-      if (creditBalance) {
-        // 更新现有记录
-        creditBalance.totalLimit = totalLimit;
-        creditBalance.updatedAt = new Date();
-        await repository.save(creditBalance);
-      } else {
-        // 创建新记录
-        creditBalance = repository.create({
-          tenantId,
-          userId,
-          totalLimit,
-          usedAmount: 0,
-          isEnabled: 1
-        });
-        await repository.save(creditBalance);
-      }
-
-      // 记录变更日志
-      const changeAmount = totalLimit - beforeTotal;
-      await this.createBalanceLog({
-        manager,
-        logRepository,
-        tenantId,
-        userId,
-        changeType: CreditBalanceChangeType.SET_LIMIT,
-        changeAmount,
-        beforeTotal,
-        afterTotal: totalLimit,
-        beforeUsed,
-        afterUsed: beforeUsed,
-        referenceId: null,
-        operatorId,
-        remark
-      });
-
-      return creditBalance;
-    });
-  }
-
-  /**
-   * 调整用户信用额度
-   */
-  async adjustLimit(params: AdjustLimitParams): Promise<CreditBalanceMt> {
-    const { tenantId, userId, adjustAmount, operatorId, remark } = params;
-
-    if (adjustAmount === 0) {
-      throw new Error('调整金额不能为0');
-    }
-
-    return await this.dataSource.transaction(async (manager) => {
-      const repository = manager.getRepository(CreditBalanceMt);
-      const logRepository = manager.getRepository(CreditBalanceLogMt);
-
-      // 查找信用额度记录
-      const creditBalance = await repository.findOne({
-        where: { tenantId, userId }
-      });
-
-      if (!creditBalance) {
-        throw new Error('用户信用额度记录不存在');
-      }
-
-      const beforeTotal = Number(creditBalance.totalLimit);
-      const beforeUsed = Number(creditBalance.usedAmount);
-      const newTotalLimit = beforeTotal + adjustAmount;
-
-      if (newTotalLimit < 0) {
-        throw new Error('调整后的总额度不能为负数');
-      }
-
-      if (newTotalLimit < beforeUsed) {
-        throw new Error('调整后的总额度不能小于已用额度');
-      }
-
-      // 更新额度
-      creditBalance.totalLimit = newTotalLimit;
-      creditBalance.updatedAt = new Date();
-      await repository.save(creditBalance);
-
-      // 记录变更日志
-      await this.createBalanceLog({
-        manager,
-        logRepository,
-        tenantId,
-        userId,
-        changeType: CreditBalanceChangeType.ADJUST,
-        changeAmount: adjustAmount,
-        beforeTotal,
-        afterTotal: newTotalLimit,
-        beforeUsed,
-        afterUsed: beforeUsed,
-        referenceId: null,
-        operatorId,
-        remark
-      });
-
-      return creditBalance;
-    });
-  }
-
-  /**
-   * 扣减信用额度(用于支付)
-   */
-  async deductAmount(params: DeductAmountParams): Promise<CreditBalanceMt> {
-    const { tenantId, userId, amount, referenceId, operatorId, remark } = params;
-
-    if (amount <= 0) {
-      throw new Error('扣减金额必须大于0');
-    }
-
-    return await this.dataSource.transaction(async (manager) => {
-      const repository = manager.getRepository(CreditBalanceMt);
-      const logRepository = manager.getRepository(CreditBalanceLogMt);
-
-      // 查找信用额度记录
-      const creditBalance = await repository.findOne({
-        where: { tenantId, userId }
-      });
-
-      if (!creditBalance) {
-        throw new Error('用户信用额度记录不存在');
-      }
-
-      if (creditBalance.isEnabled === 0) {
-        throw new Error('用户信用额度已禁用');
-      }
-
-      const beforeTotal = Number(creditBalance.totalLimit);
-      const beforeUsed = Number(creditBalance.usedAmount);
-      const newUsedAmount = beforeUsed + amount;
-
-      // 检查额度是否足够
-      if (newUsedAmount > beforeTotal) {
-        throw new Error('信用额度不足');
-      }
-
-      // 更新已用额度
-      creditBalance.usedAmount = newUsedAmount;
-      creditBalance.updatedAt = new Date();
-      await repository.save(creditBalance);
-
-      // 记录变更日志
-      await this.createBalanceLog({
-        manager,
-        logRepository,
-        tenantId,
-        userId,
-        changeType: CreditBalanceChangeType.PAYMENT,
-        changeAmount: -amount, // 扣减为负数
-        beforeTotal,
-        afterTotal: beforeTotal,
-        beforeUsed,
-        afterUsed: newUsedAmount,
-        referenceId: referenceId || null,
-        operatorId,
-        remark
-      });
-
-      return creditBalance;
-    });
-  }
-
-  /**
-   * 恢复信用额度(用于取消订单、退款等)
-   */
-  async restoreAmount(params: RestoreAmountParams): Promise<CreditBalanceMt> {
-    const { tenantId, userId, amount, changeType, referenceId, operatorId, remark } = params;
-
-    if (amount <= 0) {
-      throw new Error('恢复金额必须大于0');
-    }
-
-    return await this.dataSource.transaction(async (manager) => {
-      const repository = manager.getRepository(CreditBalanceMt);
-      const logRepository = manager.getRepository(CreditBalanceLogMt);
-
-      // 查找信用额度记录
-      const creditBalance = await repository.findOne({
-        where: { tenantId, userId }
-      });
-
-      if (!creditBalance) {
-        throw new Error('用户信用额度记录不存在');
-      }
-
-      const beforeTotal = Number(creditBalance.totalLimit);
-      const beforeUsed = Number(creditBalance.usedAmount);
-      const newUsedAmount = beforeUsed - amount;
-
-      // 检查恢复金额是否合理
-      if (newUsedAmount < 0) {
-        throw new Error('恢复金额不能超过已用额度');
-      }
-
-      // 更新已用额度
-      creditBalance.usedAmount = newUsedAmount;
-      creditBalance.updatedAt = new Date();
-      await repository.save(creditBalance);
-
-      // 记录变更日志
-      await this.createBalanceLog({
-        manager,
-        logRepository,
-        tenantId,
-        userId,
-        changeType,
-        changeAmount: amount, // 恢复为正数
-        beforeTotal,
-        afterTotal: beforeTotal,
-        beforeUsed,
-        afterUsed: newUsedAmount,
-        referenceId: referenceId || null,
-        operatorId,
-        remark
-      });
-
-      return creditBalance;
-    });
-  }
-
-  /**
-   * 取消订单恢复额度(供订单模块调用)
-   */
-  async restoreBalanceForCancelOrder(
-    tenantId: number,
-    userId: number,
-    orderId: string,
-    amount: number,
-    operatorId?: number
-  ): Promise<CreditBalanceMt> {
-    return this.restoreAmount({
-      tenantId,
-      userId,
-      amount,
-      changeType: CreditBalanceChangeType.CANCEL_ORDER,
-      referenceId: orderId,
-      operatorId,
-      remark: `取消订单恢复额度,订单号:${orderId}`
-    });
-  }
-
-  /**
-   * 退款恢复额度(供支付模块调用)
-   */
-  async restoreBalanceForRefund(
-    tenantId: number,
-    userId: number,
-    orderId: string,
-    refundAmount: number,
-    operatorId?: number
-  ): Promise<CreditBalanceMt> {
-    return this.restoreAmount({
-      tenantId,
-      userId,
-      amount: refundAmount,
-      changeType: CreditBalanceChangeType.REFUND,
-      referenceId: orderId,
-      operatorId,
-      remark: `退款恢复额度,订单号:${orderId},退款金额:${refundAmount}`
-    });
-  }
-
-  /**
-   * 查询用户信用额度
-   */
-  async getBalance(tenantId: number, userId: number): Promise<CreditBalanceMt | null> {
-    return await this.creditBalanceRepository.findOne({
-      where: { tenantId, userId }
-    });
-  }
-
-  /**
-   * 查询用户额度变更记录
-   */
-  async getBalanceLogs(
-    tenantId: number,
-    userId: number,
-    page: number = 1,
-    pageSize: number = 20
-  ): Promise<[CreditBalanceLogMt[], number]> {
-    const skip = (page - 1) * pageSize;
-
-    return await this.creditBalanceLogRepository.findAndCount({
-      where: { tenantId, userId },
-      order: { createdAt: 'DESC' },
-      skip,
-      take: pageSize
-    });
-  }
-
-  /**
-   * 创建额度变更日志(内部方法)
-   */
-  private async createBalanceLog(params: {
-    manager: EntityManager;
-    logRepository: Repository<CreditBalanceLogMt>;
-    tenantId: number;
-    userId: number;
-    changeType: CreditBalanceChangeType;
-    changeAmount: number;
-    beforeTotal: number | null;
-    afterTotal: number | null;
-    beforeUsed: number | null;
-    afterUsed: number | null;
-    referenceId: string | null;
-    operatorId?: number;
-    remark?: string;
-  }): Promise<CreditBalanceLogMt> {
-    const {
-      logRepository,
-      tenantId,
-      userId,
-      changeType,
-      changeAmount,
-      beforeTotal,
-      afterTotal,
-      beforeUsed,
-      afterUsed,
-      referenceId,
-      operatorId,
-      remark
-    } = params;
-
-    const log = logRepository.create({
-      tenantId,
-      userId,
-      changeType,
-      changeAmount,
-      beforeTotal,
-      afterTotal,
-      beforeUsed,
-      afterUsed,
-      referenceId,
-      operatorId,
-      remark
-    });
-
-    return await logRepository.save(log);
-  }
-}

+ 0 - 1
packages/credit-balance-module-mt/src/services/index.ts

@@ -1 +0,0 @@
-export * from './credit-balance.service';

+ 0 - 2
packages/credit-balance-module-mt/src/types/index.ts

@@ -1,2 +0,0 @@
-export * from '../services/credit-balance.service';
-export * from '../entities';

+ 0 - 309
packages/credit-balance-module-mt/tests/integration/credit-balance-routes.integration.test.ts

@@ -1,309 +0,0 @@
-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 creditBalanceRoutes from '../../src/routes';
-import { CreditBalanceMt, CreditBalanceLogMt, CreditBalanceChangeType } from '../../src/entities';
-import { CreditBalanceTestDataFactory } from '../utils/test-data-factory';
-
-// 设置集成测试钩子
-setupIntegrationDatabaseHooksWithEntities([
-  UserEntityMt, RoleMt, FileMt, CreditBalanceMt, CreditBalanceLogMt
-])
-
-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(data.totalLimit).toBe(10000);
-        expect(data.availableAmount).toBe(10000);
-      }
-    });
-  });
-
-  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 response = await client.payment.$post({
-        json: {
-          amount: 500.00,
-          referenceId: 'ORD202412010001',
-          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
-      }
-    });
-  });
-
-  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);
-        expect(data.data[0].changeAmount).toBeCloseTo(-500, 2);
-        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);
-      }
-    });
-  });
-});

+ 0 - 452
packages/credit-balance-module-mt/tests/unit/credit-balance.service.test.ts

@@ -1,452 +0,0 @@
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { DataSource, Repository } from 'typeorm';
-import { CreditBalanceService } from '../../src/services';
-import { CreditBalanceMt, CreditBalanceLogMt, CreditBalanceChangeType } from '../../src/entities';
-
-describe('CreditBalanceService', () => {
-  let service: CreditBalanceService;
-  let mockDataSource: DataSource;
-  let mockCreditBalanceRepository: Repository<CreditBalanceMt>;
-  let mockCreditBalanceLogRepository: Repository<CreditBalanceLogMt>;
-
-  beforeEach(() => {
-    mockCreditBalanceRepository = {
-      findOne: vi.fn(),
-      save: vi.fn(),
-      create: vi.fn(),
-      findAndCount: vi.fn()
-    } as any;
-
-    mockCreditBalanceLogRepository = {
-      save: vi.fn(),
-      create: vi.fn(),
-      findAndCount: vi.fn()
-    } as any;
-
-    mockDataSource = {
-      getRepository: vi.fn((entity) => {
-        if (entity === CreditBalanceMt) {
-          return mockCreditBalanceRepository;
-        }
-        if (entity === CreditBalanceLogMt) {
-          return mockCreditBalanceLogRepository;
-        }
-        return {} as any;
-      }),
-      transaction: vi.fn(async (callback) => {
-        const mockManager = {
-          getRepository: vi.fn((entity) => {
-            if (entity === CreditBalanceMt) {
-              return mockCreditBalanceRepository;
-            }
-            if (entity === CreditBalanceLogMt) {
-              return mockCreditBalanceLogRepository;
-            }
-            return {} as any;
-          })
-        };
-        return await callback(mockManager);
-      })
-    } as any;
-
-    service = new CreditBalanceService(mockDataSource);
-  });
-
-  describe('setLimit', () => {
-    it('应该创建新的信用额度记录', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        operatorId: 1,
-        remark: '初始化额度'
-      };
-
-      const mockCreditBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 0,
-        availableAmount: 10000,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(null);
-      vi.mocked(mockCreditBalanceRepository.create).mockReturnValue(mockCreditBalance);
-      vi.mocked(mockCreditBalanceRepository.save).mockResolvedValue(mockCreditBalance);
-      vi.mocked(mockCreditBalanceLogRepository.create).mockReturnValue({} as any);
-      vi.mocked(mockCreditBalanceLogRepository.save).mockResolvedValue({} as any);
-
-      const result = await service.setLimit(params);
-
-      expect(result).toEqual(mockCreditBalance);
-      expect(mockCreditBalanceRepository.findOne).toHaveBeenCalledWith({
-        where: { tenantId: 1, userId: 1001 }
-      });
-      expect(mockCreditBalanceRepository.create).toHaveBeenCalledWith({
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 0,
-        isEnabled: 1
-      });
-    });
-
-    it('应该更新现有的信用额度记录', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 15000,
-        operatorId: 1,
-        remark: '提升额度'
-      };
-
-      const existingBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 500,
-        availableAmount: 9500,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      const updatedBalance = {
-        ...existingBalance,
-        totalLimit: 15000,
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(existingBalance);
-      vi.mocked(mockCreditBalanceRepository.save).mockResolvedValue(updatedBalance);
-      vi.mocked(mockCreditBalanceLogRepository.create).mockReturnValue({} as any);
-      vi.mocked(mockCreditBalanceLogRepository.save).mockResolvedValue({} as any);
-
-      const result = await service.setLimit(params);
-
-      expect(result.totalLimit).toBe(15000);
-      expect(mockCreditBalanceRepository.save).toHaveBeenCalledWith(updatedBalance);
-    });
-  });
-
-  describe('adjustLimit', () => {
-    it('应该成功增加额度', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        adjustAmount: 5000,
-        operatorId: 1,
-        remark: '增加额度'
-      };
-
-      const existingBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 500,
-        availableAmount: 9500,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      const updatedBalance = {
-        ...existingBalance,
-        totalLimit: 15000,
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(existingBalance);
-      vi.mocked(mockCreditBalanceRepository.save).mockResolvedValue(updatedBalance);
-      vi.mocked(mockCreditBalanceLogRepository.create).mockReturnValue({} as any);
-      vi.mocked(mockCreditBalanceLogRepository.save).mockResolvedValue({} as any);
-
-      const result = await service.adjustLimit(params);
-
-      expect(result.totalLimit).toBe(15000);
-    });
-
-    it('应该成功减少额度', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        adjustAmount: -2000,
-        operatorId: 1,
-        remark: '减少额度'
-      };
-
-      const existingBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 500,
-        availableAmount: 9500,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      const updatedBalance = {
-        ...existingBalance,
-        totalLimit: 8000,
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(existingBalance);
-      vi.mocked(mockCreditBalanceRepository.save).mockResolvedValue(updatedBalance);
-      vi.mocked(mockCreditBalanceLogRepository.create).mockReturnValue({} as any);
-      vi.mocked(mockCreditBalanceLogRepository.save).mockResolvedValue({} as any);
-
-      const result = await service.adjustLimit(params);
-
-      expect(result.totalLimit).toBe(8000);
-    });
-
-    it('当调整金额为0时应该抛出错误', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        adjustAmount: 0,
-        operatorId: 1,
-        remark: '无效调整'
-      };
-
-      await expect(service.adjustLimit(params)).rejects.toThrow('调整金额不能为0');
-    });
-
-    it('当调整后的额度小于已用额度时应该抛出错误', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        adjustAmount: -8000,
-        operatorId: 1,
-        remark: '过度减少额度'
-      };
-
-      const existingBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 5000,
-        availableAmount: 5000,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(existingBalance);
-
-      await expect(service.adjustLimit(params)).rejects.toThrow('调整后的总额度不能小于已用额度');
-    });
-  });
-
-  describe('deductAmount', () => {
-    it('应该成功扣减额度', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        amount: 500,
-        referenceId: 'ORD202412010001',
-        operatorId: 1,
-        remark: '订单支付'
-      };
-
-      const existingBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 0,
-        availableAmount: 10000,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      const updatedBalance = {
-        ...existingBalance,
-        usedAmount: 500,
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(existingBalance);
-      vi.mocked(mockCreditBalanceRepository.save).mockResolvedValue(updatedBalance);
-      vi.mocked(mockCreditBalanceLogRepository.create).mockReturnValue({} as any);
-      vi.mocked(mockCreditBalanceLogRepository.save).mockResolvedValue({} as any);
-
-      const result = await service.deductAmount(params);
-
-      expect(result.usedAmount).toBe(500);
-    });
-
-    it('当额度不足时应该抛出错误', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        amount: 15000,
-        referenceId: 'ORD202412010001',
-        operatorId: 1,
-        remark: '大额订单支付'
-      };
-
-      const existingBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 0,
-        availableAmount: 10000,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(existingBalance);
-
-      await expect(service.deductAmount(params)).rejects.toThrow('信用额度不足');
-    });
-
-    it('当额度已禁用时应该抛出错误', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        amount: 500,
-        referenceId: 'ORD202412010001',
-        operatorId: 1,
-        remark: '订单支付'
-      };
-
-      const existingBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 0,
-        availableAmount: 10000,
-        isEnabled: 0,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(existingBalance);
-
-      await expect(service.deductAmount(params)).rejects.toThrow('用户信用额度已禁用');
-    });
-  });
-
-  describe('restoreAmount', () => {
-    it('应该成功恢复额度', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        amount: 500,
-        changeType: CreditBalanceChangeType.CANCEL_ORDER,
-        referenceId: 'ORD202412010001',
-        operatorId: 1,
-        remark: '取消订单恢复额度'
-      };
-
-      const existingBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 2000,
-        availableAmount: 8000,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      const updatedBalance = {
-        ...existingBalance,
-        usedAmount: 1500,
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(existingBalance);
-      vi.mocked(mockCreditBalanceRepository.save).mockResolvedValue(updatedBalance);
-      vi.mocked(mockCreditBalanceLogRepository.create).mockReturnValue({} as any);
-      vi.mocked(mockCreditBalanceLogRepository.save).mockResolvedValue({} as any);
-
-      const result = await service.restoreAmount(params);
-
-      expect(result.usedAmount).toBe(1500);
-    });
-
-    it('当恢复金额超过已用额度时应该抛出错误', async () => {
-      const params = {
-        tenantId: 1,
-        userId: 1001,
-        amount: 3000,
-        changeType: CreditBalanceChangeType.REFUND,
-        referenceId: 'ORD202412010001',
-        operatorId: 1,
-        remark: '退款恢复额度'
-      };
-
-      const existingBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 2000,
-        availableAmount: 8000,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(existingBalance);
-
-      await expect(service.restoreAmount(params)).rejects.toThrow('恢复金额不能超过已用额度');
-    });
-  });
-
-  describe('getBalance', () => {
-    it('应该返回用户信用额度', async () => {
-      const tenantId = 1;
-      const userId = 1001;
-
-      const mockBalance = {
-        id: 1,
-        tenantId: 1,
-        userId: 1001,
-        totalLimit: 10000,
-        usedAmount: 500,
-        availableAmount: 9500,
-        isEnabled: 1,
-        createdAt: new Date(),
-        updatedAt: new Date()
-      };
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(mockBalance);
-
-      const result = await service.getBalance(tenantId, userId);
-
-      expect(result).toEqual(mockBalance);
-      expect(mockCreditBalanceRepository.findOne).toHaveBeenCalledWith({
-        where: { tenantId, userId }
-      });
-    });
-
-    it('当用户没有信用额度时应该返回null', async () => {
-      const tenantId = 1;
-      const userId = 9999;
-
-      vi.mocked(mockCreditBalanceRepository.findOne).mockResolvedValue(null);
-
-      const result = await service.getBalance(tenantId, userId);
-
-      expect(result).toBeNull();
-    });
-  });
-});

+ 0 - 55
packages/credit-balance-module-mt/tests/utils/test-data-factory.ts

@@ -1,55 +0,0 @@
-import { DataSource } from 'typeorm';
-import { UserEntityMt } from '@d8d/core-module-mt/user-module-mt/entities';
-import { JWTUtil } from '@d8d/shared-utils';
-
-/**
- * 信用额度模块测试数据工厂类
- */
-export class CreditBalanceTestDataFactory {
-  /**
-   * 创建测试用户数据
-   */
-  static createUserData(overrides: Partial<UserEntityMt> = {}): Partial<UserEntityMt> {
-    const timestamp = Math.floor(Math.random() * 100000);
-    return {
-      username: `test_user_${timestamp}`,
-      password: 'test_password',
-      nickname: '测试用户',
-      registrationSource: 'web',
-      state: 1,
-      ...overrides
-    };
-  }
-
-  /**
-   * 在数据库中创建测试用户
-   */
-  static async createTestUser(dataSource: DataSource, tenantId: number, overrides: Partial<UserEntityMt> = {}): Promise<UserEntityMt> {
-    const userData = this.createUserData({ tenantId, ...overrides });
-    const userRepository = dataSource.getRepository(UserEntityMt);
-    const user = userRepository.create(userData);
-    return await userRepository.save(user);
-  }
-
-  /**
-   * 为测试用户生成JWT token
-   */
-  static generateUserToken(user: UserEntityMt): string {
-    return JWTUtil.generateToken({
-      id: user.id,
-      username: user.username,
-      tenantId: user.tenantId
-    });
-  }
-
-  /**
-   * 为管理员生成JWT token
-   */
-  static generateAdminToken(tenantId: number): string {
-    return JWTUtil.generateToken({
-      id: 1,
-      username: 'admin',
-      tenantId
-    });
-  }
-}

+ 0 - 16
packages/credit-balance-module-mt/tsconfig.json

@@ -1,16 +0,0 @@
-{
-  "extends": "../../tsconfig.json",
-  "compilerOptions": {
-    "composite": true,
-    "rootDir": ".",
-    "outDir": "dist"
-  },
-  "include": [
-    "src/**/*",
-    "tests/**/*"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
-}

+ 0 - 21
packages/credit-balance-module-mt/vitest.config.ts

@@ -1,21 +0,0 @@
-import { defineConfig } from 'vitest/config';
-
-export default defineConfig({
-  test: {
-    globals: true,
-    environment: 'node',
-    include: ['tests/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
-    coverage: {
-      provider: 'v8',
-      reporter: ['text', 'json', 'html'],
-      exclude: [
-        'tests/**',
-        '**/*.d.ts',
-        '**/*.config.*',
-        '**/dist/**'
-      ]
-    },
-    // 关闭并行测试以避免数据库连接冲突
-    fileParallelism: false
-  }
-});