feat: add access number routing and admin list improvements
This commit is contained in:
@@ -10,6 +10,10 @@ function createPrismaMock() {
|
||||
status: 'active',
|
||||
cmppAccount: '100001',
|
||||
cmppEnterpriseCode: 'APP-EC',
|
||||
cmppApplicationExtension: '0001',
|
||||
cmppAccessNumberFillEnabled: true,
|
||||
cmppAccessNumberFillPrefix: '00',
|
||||
cmppClientSrcId: '000001',
|
||||
cmppMaxConnections: 2,
|
||||
cmppWindowSize: 32,
|
||||
interfaceEnabled: true,
|
||||
@@ -24,6 +28,10 @@ function createPrismaMock() {
|
||||
status: 'active',
|
||||
cmppAccount: '100001',
|
||||
cmppEnterpriseCode: 'APP-EC',
|
||||
cmppApplicationExtension: '0001',
|
||||
cmppAccessNumberFillEnabled: true,
|
||||
cmppAccessNumberFillPrefix: '00',
|
||||
cmppClientSrcId: '000001',
|
||||
cmppMaxConnections: 2,
|
||||
cmppWindowSize: 32,
|
||||
interfaceEnabled: true,
|
||||
@@ -225,6 +233,33 @@ describe('SmsConfigService', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('sorts enterprise applications by today send count descending with a stable name tie-breaker', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
const baseApplication = {
|
||||
tenantId: 'tenant-1',
|
||||
status: 'active',
|
||||
interfaceEnabled: true,
|
||||
tenant: { id: 'tenant-1', name: '租户A', code: 'TENANT-A' },
|
||||
ipAllowlist: [],
|
||||
};
|
||||
prisma.smsApplication.findMany.mockResolvedValue([
|
||||
{ ...baseApplication, id: 'app-1', name: '乙应用' },
|
||||
{ ...baseApplication, id: 'app-2', name: '甲应用' },
|
||||
{ ...baseApplication, id: 'app-3', name: '丙应用' },
|
||||
]);
|
||||
prisma.cmppDownstreamConnection.findMany.mockResolvedValue([]);
|
||||
prisma.smsMessageRecord.groupBy.mockResolvedValue([
|
||||
{ applicationId: 'app-1', status: 'delivered', _count: { _all: 2 } },
|
||||
{ applicationId: 'app-2', status: 'delivered', _count: { _all: 2 } },
|
||||
{ applicationId: 'app-3', status: 'delivered', _count: { _all: 5 } },
|
||||
]);
|
||||
const service = new SmsConfigService(prisma as never);
|
||||
|
||||
const applications = await service.listApplications({ includeConnections: true });
|
||||
|
||||
expect(applications.map((application) => application.id)).toEqual(['app-3', 'app-2', 'app-1']);
|
||||
});
|
||||
|
||||
it('returns CMPP params from persisted application and channel config', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
const service = new SmsConfigService(prisma as never);
|
||||
@@ -235,6 +270,10 @@ describe('SmsConfigService', () => {
|
||||
account: '100001',
|
||||
enterpriseCode: 'APP-EC',
|
||||
passwordCipher: '0123456789abcdef',
|
||||
srcId: '000001',
|
||||
applicationExtension: '0001',
|
||||
accessNumberFillEnabled: true,
|
||||
accessNumberFillPrefix: '00',
|
||||
gatewayHost: '127.0.0.1',
|
||||
gatewayPort: 17890,
|
||||
interfaceEnabled: true,
|
||||
@@ -283,6 +322,54 @@ describe('SmsConfigService', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('persists a filled client Src_Id separately from the real application extension', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
prisma.smsApplication.findUnique.mockResolvedValueOnce(null).mockResolvedValueOnce(null);
|
||||
const service = new SmsConfigService(prisma as never);
|
||||
|
||||
await service.createApplication({
|
||||
tenantId: 'tenant-1',
|
||||
name: '接入号应用',
|
||||
cmppAccount: '123456',
|
||||
passwordCipher: '1234567890abcdef',
|
||||
cmppApplicationExtension: '0001',
|
||||
cmppAccessNumberFillEnabled: true,
|
||||
cmppAccessNumberFillPrefix: '00',
|
||||
});
|
||||
|
||||
expect(prisma.smsApplication.create).toHaveBeenCalledWith(expect.objectContaining({
|
||||
data: expect.objectContaining({
|
||||
cmppApplicationExtension: '0001',
|
||||
cmppAccessNumberFillEnabled: true,
|
||||
cmppAccessNumberFillPrefix: '00',
|
||||
cmppClientSrcId: '000001',
|
||||
}),
|
||||
}));
|
||||
});
|
||||
|
||||
it('rejects access number filling without a numeric prefix and application extension', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
prisma.smsApplication.findUnique.mockResolvedValue(null);
|
||||
const service = new SmsConfigService(prisma as never);
|
||||
|
||||
await expect(service.createApplication({
|
||||
tenantId: 'tenant-1',
|
||||
name: '缺少扩展码',
|
||||
cmppAccount: '123456',
|
||||
cmppAccessNumberFillEnabled: true,
|
||||
cmppAccessNumberFillPrefix: '00',
|
||||
})).rejects.toThrow('cmppApplicationExtension is required');
|
||||
|
||||
await expect(service.createApplication({
|
||||
tenantId: 'tenant-1',
|
||||
name: '错误前缀',
|
||||
cmppAccount: '123456',
|
||||
cmppApplicationExtension: '0001',
|
||||
cmppAccessNumberFillEnabled: true,
|
||||
cmppAccessNumberFillPrefix: 'AB',
|
||||
})).rejects.toThrow('cmppAccessNumberFillPrefix must contain digits only');
|
||||
});
|
||||
|
||||
it('rejects invalid enterprise application queue priority', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
const service = new SmsConfigService(prisma as never);
|
||||
|
||||
Reference in New Issue
Block a user