845 lines
24 KiB
TypeScript
845 lines
24 KiB
TypeScript
import { createHash } from 'node:crypto';
|
|
|
|
import { PrismaClient } from '@prisma/client';
|
|
import { hashPasswordArgon2id } from '../packages/auth/src/index';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
const ACTOR_ID = 'usr_test_admin';
|
|
const TEST_PASSWORD = 'Test@123456';
|
|
|
|
const permissions = [
|
|
'dashboard.view',
|
|
'active_calls.view',
|
|
'active_calls.manage',
|
|
'customers.view',
|
|
'customers.manage',
|
|
'customer_gateways.view',
|
|
'customer_gateways.manage',
|
|
'vendors.view',
|
|
'vendors.manage',
|
|
'vendor_gateways.view',
|
|
'vendor_gateways.manage',
|
|
'line_groups.view',
|
|
'line_groups.manage',
|
|
'number_library.view',
|
|
'number_library.manage',
|
|
'recharges.view',
|
|
'recharges.manage',
|
|
'cdr.view',
|
|
'recordings.play',
|
|
'quality.view',
|
|
'quality.manage',
|
|
'users.view',
|
|
'users.manage',
|
|
'roles.view',
|
|
'roles.manage',
|
|
'audit.view',
|
|
] as const;
|
|
|
|
const roles = [
|
|
{ id: 'ROLE_TEST_ADMIN', name: '测试管理员', permissionIds: [...permissions] },
|
|
{
|
|
id: 'ROLE_TEST_VIEWER',
|
|
name: '测试只读员',
|
|
permissionIds: permissions.filter((permission) => permission.endsWith('.view') || permission === 'cdr.view'),
|
|
},
|
|
{ id: 'ROLE_TEST_FINANCE', name: '测试财务员', permissionIds: ['customers.view', 'recharges.view', 'recharges.manage'] },
|
|
{ id: 'ROLE_TEST_QUALITY', name: '测试质检员', permissionIds: ['quality.view', 'quality.manage', 'recordings.play', 'cdr.view'] },
|
|
{
|
|
id: 'ROLE_TEST_GATEWAY',
|
|
name: '测试客户网关员',
|
|
permissionIds: ['customers.view', 'customer_gateways.view', 'customer_gateways.manage', 'line_groups.view'],
|
|
},
|
|
{
|
|
id: 'ROLE_TEST_VENDOR',
|
|
name: '测试供应商线路员',
|
|
permissionIds: ['vendors.view', 'vendors.manage', 'vendor_gateways.view', 'vendor_gateways.manage', 'line_groups.view', 'line_groups.manage'],
|
|
},
|
|
{ id: 'ROLE_TEST_ACTIVE', name: '测试话务员', permissionIds: ['active_calls.view', 'active_calls.manage'] },
|
|
{ id: 'ROLE_TEST_AUDIT', name: '测试审计员', permissionIds: ['audit.view'] },
|
|
] as const;
|
|
|
|
const users = [
|
|
{ id: ACTOR_ID, username: 'test.admin', displayName: '测试管理员', roleId: 'ROLE_TEST_ADMIN' },
|
|
{ id: 'usr_test_viewer', username: 'test.viewer', displayName: '测试只读员', roleId: 'ROLE_TEST_VIEWER' },
|
|
{ id: 'usr_test_fin', username: 'test.finance', displayName: '测试财务员', roleId: 'ROLE_TEST_FINANCE' },
|
|
{ id: 'usr_test_quality', username: 'test.quality', displayName: '测试质检员', roleId: 'ROLE_TEST_QUALITY' },
|
|
{ id: 'usr_test_gateway', username: 'test.gateway', displayName: '测试客户网关员', roleId: 'ROLE_TEST_GATEWAY' },
|
|
{ id: 'usr_test_vendor', username: 'test.vendor', displayName: '测试供应商线路员', roleId: 'ROLE_TEST_VENDOR' },
|
|
{ id: 'usr_test_active', username: 'test.active', displayName: '测试话务员', roleId: 'ROLE_TEST_ACTIVE' },
|
|
{ id: 'usr_test_audit', username: 'test.audit', displayName: '测试审计员', roleId: 'ROLE_TEST_AUDIT' },
|
|
] as const;
|
|
|
|
function sipHa1(username: string, domain: string, password: string): string {
|
|
return createHash('md5').update(`${username}:${domain}:${password}`).digest('hex');
|
|
}
|
|
|
|
async function seedAuth() {
|
|
for (const id of permissions) {
|
|
const [module, action] = id.split('.');
|
|
await prisma.permission.upsert({
|
|
where: { id },
|
|
update: {},
|
|
create: {
|
|
id,
|
|
module,
|
|
action,
|
|
description: `测试权限 ${id}`,
|
|
},
|
|
});
|
|
}
|
|
|
|
for (const role of roles) {
|
|
await prisma.role.upsert({
|
|
where: { id: role.id },
|
|
update: {
|
|
name: role.name,
|
|
status: 'ENABLED',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: role.id,
|
|
name: role.name,
|
|
description: '自动化测试角色',
|
|
builtIn: false,
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
for (const permissionId of role.permissionIds) {
|
|
await prisma.rolePermission.upsert({
|
|
where: { roleId_permissionId: { roleId: role.id, permissionId } },
|
|
update: {},
|
|
create: { roleId: role.id, permissionId, createdBy: ACTOR_ID },
|
|
});
|
|
}
|
|
}
|
|
|
|
const passwordHash = await hashPasswordArgon2id(TEST_PASSWORD, { memoryKiB: 1024, passes: 1 });
|
|
for (const user of users) {
|
|
await prisma.user.upsert({
|
|
where: { id: user.id },
|
|
update: {
|
|
username: user.username,
|
|
displayName: user.displayName,
|
|
passwordHash,
|
|
passwordAlgo: 'argon2id',
|
|
status: 'ENABLED',
|
|
failedLoginCount: 0,
|
|
lockedUntil: null,
|
|
requirePasswordChange: false,
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: user.id,
|
|
username: user.username,
|
|
displayName: user.displayName,
|
|
email: `${user.username}@example.test`,
|
|
passwordHash,
|
|
passwordAlgo: 'argon2id',
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.userRole.upsert({
|
|
where: { userId_roleId: { userId: user.id, roleId: user.roleId } },
|
|
update: {},
|
|
create: { userId: user.id, roleId: user.roleId, createdBy: ACTOR_ID },
|
|
});
|
|
}
|
|
}
|
|
|
|
async function seedNumberLibrary() {
|
|
await prisma.geoCity.upsert({
|
|
where: { code: 'geo_340100' },
|
|
update: {
|
|
provinceCode: '340000',
|
|
provinceName: '安徽省',
|
|
cityCode: '340100',
|
|
cityName: '合肥市',
|
|
cityLevel: '地级市',
|
|
status: 'ENABLED',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
code: 'geo_340100',
|
|
provinceCode: '340000',
|
|
provinceName: '安徽省',
|
|
cityCode: '340100',
|
|
cityName: '合肥市',
|
|
cityLevel: '地级市',
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.phoneNumberSegment.upsert({
|
|
where: { segment7: '1380013' },
|
|
update: {
|
|
cityCode: '340100',
|
|
provinceName: '安徽省',
|
|
cityName: '合肥市',
|
|
carrier: 'MOBILE',
|
|
source: 'test-seed',
|
|
batchId: 'test-seed',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
segment7: '1380013',
|
|
cityCode: '340100',
|
|
provinceName: '安徽省',
|
|
cityName: '合肥市',
|
|
carrier: 'MOBILE',
|
|
source: 'test-seed',
|
|
batchId: 'test-seed',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.phoneAreaCode.upsert({
|
|
where: { areaCode: '0551' },
|
|
update: {
|
|
cityCode: '340100',
|
|
provinceName: '安徽省',
|
|
cityName: '合肥市',
|
|
source: 'test-seed',
|
|
batchId: 'test-seed',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
areaCode: '0551',
|
|
cityCode: '340100',
|
|
provinceName: '安徽省',
|
|
cityName: '合肥市',
|
|
source: 'test-seed',
|
|
batchId: 'test-seed',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.carrierPrefixRule.upsert({
|
|
where: { prefix: '138' },
|
|
update: {
|
|
carrier: 'MOBILE',
|
|
priority: 10,
|
|
source: 'test-seed',
|
|
batchId: 'test-seed',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
prefix: '138',
|
|
carrier: 'MOBILE',
|
|
priority: 10,
|
|
source: 'test-seed',
|
|
batchId: 'test-seed',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
}
|
|
|
|
async function seedBusinessData() {
|
|
await prisma.customer.upsert({
|
|
where: { id: 'cus_auto_001' },
|
|
update: {
|
|
name: '自动化测试客户A',
|
|
contactName: '测试联系人',
|
|
phone: '13800138000',
|
|
email: 'customer-a@example.test',
|
|
domain: 'customer-a.example.test',
|
|
status: 'ENABLED',
|
|
billingMode: 'PREPAID',
|
|
balance: '1000.000000',
|
|
creditLimit: '200.000000',
|
|
minBalance: '10.000000',
|
|
notes: '自动化测试固定客户,可用于充值、扣款、网关和话单测试',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: 'cus_auto_001',
|
|
name: '自动化测试客户A',
|
|
contactName: '测试联系人',
|
|
phone: '13800138000',
|
|
email: 'customer-a@example.test',
|
|
domain: 'customer-a.example.test',
|
|
status: 'ENABLED',
|
|
billingMode: 'PREPAID',
|
|
balance: '1000.000000',
|
|
creditLimit: '200.000000',
|
|
minBalance: '10.000000',
|
|
notes: '自动化测试固定客户,可用于充值、扣款、网关和话单测试',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.customer.upsert({
|
|
where: { id: 'cus_low_001' },
|
|
update: {
|
|
name: '自动化低余额客户',
|
|
status: 'ENABLED',
|
|
billingMode: 'PREPAID',
|
|
balance: '3.000000',
|
|
creditLimit: '0.000000',
|
|
minBalance: '10.000000',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: 'cus_low_001',
|
|
name: '自动化低余额客户',
|
|
domain: 'customer-low.example.test',
|
|
status: 'ENABLED',
|
|
billingMode: 'PREPAID',
|
|
balance: '3.000000',
|
|
creditLimit: '0.000000',
|
|
minBalance: '10.000000',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
const businessPrefixes = [
|
|
{ id: 'bp_auto_671', prefix: '671', name: '自动化业务前缀671', priority: 10 },
|
|
{ id: 'bp_auto_672', prefix: '672', name: '自动化业务前缀672', priority: 20 },
|
|
] as const;
|
|
for (const prefix of businessPrefixes) {
|
|
await prisma.businessPrefix.upsert({
|
|
where: { id: prefix.id },
|
|
update: {
|
|
prefix: prefix.prefix,
|
|
name: prefix.name,
|
|
description: '自动化测试业务前缀',
|
|
priority: prefix.priority,
|
|
status: 'ENABLED',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: prefix.id,
|
|
prefix: prefix.prefix,
|
|
name: prefix.name,
|
|
description: '自动化测试业务前缀',
|
|
priority: prefix.priority,
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
}
|
|
|
|
await prisma.vendor.upsert({
|
|
where: { id: 'ven_auto_001' },
|
|
update: {
|
|
name: '自动化测试供应商A',
|
|
contactName: '供应商联系人',
|
|
phone: '13900139000',
|
|
email: 'vendor-a@example.test',
|
|
status: 'ENABLED',
|
|
balance: '5000.000000',
|
|
creditLimit: '500.000000',
|
|
settlement: '月结',
|
|
notes: '自动化测试固定供应商',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: 'ven_auto_001',
|
|
name: '自动化测试供应商A',
|
|
contactName: '供应商联系人',
|
|
phone: '13900139000',
|
|
email: 'vendor-a@example.test',
|
|
status: 'ENABLED',
|
|
balance: '5000.000000',
|
|
creditLimit: '500.000000',
|
|
settlement: '月结',
|
|
notes: '自动化测试固定供应商',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
const vendorGateways = [
|
|
{ id: 'vgw_auto_primary', name: '自动化主落地网关', host: '10.88.0.10', priority: 10, weight: 70 },
|
|
{ id: 'vgw_auto_backup', name: '自动化备落地网关', host: '10.88.0.11', priority: 20, weight: 30 },
|
|
] as const;
|
|
for (const gateway of vendorGateways) {
|
|
await prisma.vendorGateway.upsert({
|
|
where: { id: gateway.id },
|
|
update: {
|
|
vendorId: 'ven_auto_001',
|
|
name: gateway.name,
|
|
authMode: 'IP',
|
|
host: gateway.host,
|
|
port: 5060,
|
|
transport: 'udp',
|
|
cpsLimit: 50,
|
|
concurrencyLimit: 500,
|
|
billingCycleSec: 60,
|
|
cycleRate: gateway.id === 'vgw_auto_primary' ? '0.035000' : '0.040000',
|
|
landingCalleePrefix: '86',
|
|
status: 'ENABLED',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: gateway.id,
|
|
vendorId: 'ven_auto_001',
|
|
name: gateway.name,
|
|
authMode: 'IP',
|
|
host: gateway.host,
|
|
port: 5060,
|
|
transport: 'udp',
|
|
cpsLimit: 50,
|
|
concurrencyLimit: 500,
|
|
billingCycleSec: 60,
|
|
cycleRate: gateway.id === 'vgw_auto_primary' ? '0.035000' : '0.040000',
|
|
landingCalleePrefix: '86',
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.vendorGatewayCodec.upsert({
|
|
where: { vendorGatewayId_codec: { vendorGatewayId: gateway.id, codec: 'PCMA' } },
|
|
update: { priority: 10, updatedBy: ACTOR_ID },
|
|
create: { id: `${gateway.id}_pcma`, vendorGatewayId: gateway.id, codec: 'PCMA', priority: 10, createdBy: ACTOR_ID, updatedBy: ACTOR_ID },
|
|
});
|
|
|
|
await prisma.vendorGatewayPrefixRule.upsert({
|
|
where: { vendorGatewayId_direction_priority: { vendorGatewayId: gateway.id, direction: 'CALLEE', priority: 10 } },
|
|
update: { matchPrefix: '671', replacePrefix: '86', updatedBy: ACTOR_ID },
|
|
create: {
|
|
id: `${gateway.id}_callee`,
|
|
vendorGatewayId: gateway.id,
|
|
direction: 'CALLEE',
|
|
matchPrefix: '671',
|
|
replacePrefix: '86',
|
|
priority: 10,
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
}
|
|
|
|
await prisma.vendorGatewayForbiddenPeriod.upsert({
|
|
where: { id: 'vgwfp_auto_001' },
|
|
update: {
|
|
vendorGatewayId: 'vgw_auto_backup',
|
|
weekdayMask: 127,
|
|
startTime: '00:00:00',
|
|
endTime: '00:10:00',
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
create: {
|
|
id: 'vgwfp_auto_001',
|
|
vendorGatewayId: 'vgw_auto_backup',
|
|
weekdayMask: 127,
|
|
startTime: '00:00:00',
|
|
endTime: '00:10:00',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.vendorGatewayCallerRewrite.upsert({
|
|
where: { id: 'vgwcr_auto_001' },
|
|
update: {
|
|
vendorGatewayId: 'vgw_auto_primary',
|
|
caller: '05510000001',
|
|
weight: 100,
|
|
status: 'ENABLED',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: 'vgwcr_auto_001',
|
|
vendorGatewayId: 'vgw_auto_primary',
|
|
caller: '05510000001',
|
|
weight: 100,
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.landingLineGroup.upsert({
|
|
where: { id: 'llg_auto_001' },
|
|
update: {
|
|
name: '自动化测试线路组',
|
|
status: 'ENABLED',
|
|
notes: '主备落地网关测试线路组',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: 'llg_auto_001',
|
|
name: '自动化测试线路组',
|
|
status: 'ENABLED',
|
|
notes: '主备落地网关测试线路组',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
for (const gateway of vendorGateways) {
|
|
await prisma.landingLineGroupItem.upsert({
|
|
where: { lineGroupId_vendorGatewayId: { lineGroupId: 'llg_auto_001', vendorGatewayId: gateway.id } },
|
|
update: {
|
|
priority: gateway.priority,
|
|
weight: gateway.weight,
|
|
concurrencyCap: gateway.id === 'vgw_auto_primary' ? 300 : 100,
|
|
status: 'ENABLED',
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
create: {
|
|
id: gateway.id === 'vgw_auto_primary' ? 'llgi_auto_primary' : 'llgi_auto_backup',
|
|
lineGroupId: 'llg_auto_001',
|
|
vendorGatewayId: gateway.id,
|
|
priority: gateway.priority,
|
|
weight: gateway.weight,
|
|
concurrencyCap: gateway.id === 'vgw_auto_primary' ? 300 : 100,
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
}
|
|
|
|
await prisma.customerGateway.upsert({
|
|
where: { id: 'cgw_auto_ip' },
|
|
update: {
|
|
customerId: 'cus_auto_001',
|
|
name: '自动化IP认证客户网关',
|
|
authMode: 'IP',
|
|
sourceIp: '10.66.0.10',
|
|
lineGroupId: 'llg_auto_001',
|
|
billingCycleSec: 60,
|
|
cycleRate: '0.080000',
|
|
callerMatchMode: 'PREFIXES',
|
|
calleeMatchMode: 'BUSINESS_PREFIXES',
|
|
status: 'ENABLED',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: 'cgw_auto_ip',
|
|
customerId: 'cus_auto_001',
|
|
name: '自动化IP认证客户网关',
|
|
authMode: 'IP',
|
|
sourceIp: '10.66.0.10',
|
|
lineGroupId: 'llg_auto_001',
|
|
billingCycleSec: 60,
|
|
cycleRate: '0.080000',
|
|
callerMatchMode: 'PREFIXES',
|
|
calleeMatchMode: 'BUSINESS_PREFIXES',
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.customerGateway.upsert({
|
|
where: { id: 'cgw_auto_sip' },
|
|
update: {
|
|
customerId: 'cus_auto_001',
|
|
name: '自动化SIP认证客户网关',
|
|
authMode: 'SIP_DIGEST',
|
|
sipUsername: 'auto_sip_user',
|
|
sipDomain: 'customer-a.example.test',
|
|
sipHa1: sipHa1('auto_sip_user', 'customer-a.example.test', TEST_PASSWORD),
|
|
lineGroupId: 'llg_auto_001',
|
|
billingCycleSec: 60,
|
|
cycleRate: '0.090000',
|
|
callerMatchMode: 'ANY',
|
|
calleeMatchMode: 'BUSINESS_PREFIXES',
|
|
status: 'ENABLED',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: 'cgw_auto_sip',
|
|
customerId: 'cus_auto_001',
|
|
name: '自动化SIP认证客户网关',
|
|
authMode: 'SIP_DIGEST',
|
|
sipUsername: 'auto_sip_user',
|
|
sipDomain: 'customer-a.example.test',
|
|
sipHa1: sipHa1('auto_sip_user', 'customer-a.example.test', TEST_PASSWORD),
|
|
lineGroupId: 'llg_auto_001',
|
|
billingCycleSec: 60,
|
|
cycleRate: '0.090000',
|
|
callerMatchMode: 'ANY',
|
|
calleeMatchMode: 'BUSINESS_PREFIXES',
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.customerGatewayIp.upsert({
|
|
where: { gatewayId_sourceIp: { gatewayId: 'cgw_auto_ip', sourceIp: '10.66.0.10' } },
|
|
update: { status: 'ENABLED', updatedBy: ACTOR_ID, deletedAt: null },
|
|
create: { id: 'cgip_auto_001', gatewayId: 'cgw_auto_ip', sourceIp: '10.66.0.10', status: 'ENABLED', createdBy: ACTOR_ID, updatedBy: ACTOR_ID },
|
|
});
|
|
|
|
await prisma.customerGatewayBusinessPrefix.upsert({
|
|
where: { gatewayId_businessPrefixId: { gatewayId: 'cgw_auto_ip', businessPrefixId: 'bp_auto_671' } },
|
|
update: {},
|
|
create: { id: 'cgbp_auto_ip_671', gatewayId: 'cgw_auto_ip', businessPrefixId: 'bp_auto_671', createdBy: ACTOR_ID },
|
|
});
|
|
|
|
await prisma.customerGatewayBusinessPrefix.upsert({
|
|
where: { gatewayId_businessPrefixId: { gatewayId: 'cgw_auto_sip', businessPrefixId: 'bp_auto_671' } },
|
|
update: {},
|
|
create: { id: 'cgbp_auto_sip_671', gatewayId: 'cgw_auto_sip', businessPrefixId: 'bp_auto_671', createdBy: ACTOR_ID },
|
|
});
|
|
|
|
await prisma.customerGatewayCallerPrefix.upsert({
|
|
where: { gatewayId_prefix: { gatewayId: 'cgw_auto_ip', prefix: '0551' } },
|
|
update: { priority: 10 },
|
|
create: { id: 'cgcp_auto_0551', gatewayId: 'cgw_auto_ip', prefix: '0551', priority: 10, createdBy: ACTOR_ID },
|
|
});
|
|
|
|
await prisma.customerGatewayPolicy.upsert({
|
|
where: { id: 'cgp_auto_001' },
|
|
update: {
|
|
customerId: 'cus_auto_001',
|
|
gatewayId: 'cgw_auto_ip',
|
|
lineGroupId: 'llg_auto_001',
|
|
name: '自动化客户网关策略',
|
|
priority: 10,
|
|
callerMode: 'PREFIX',
|
|
callerValue: '0551',
|
|
calleeMode: 'PREFIX',
|
|
calleeValue: '671',
|
|
status: 'ENABLED',
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: 'cgp_auto_001',
|
|
customerId: 'cus_auto_001',
|
|
gatewayId: 'cgw_auto_ip',
|
|
lineGroupId: 'llg_auto_001',
|
|
name: '自动化客户网关策略',
|
|
priority: 10,
|
|
callerMode: 'PREFIX',
|
|
callerValue: '0551',
|
|
calleeMode: 'PREFIX',
|
|
calleeValue: '671',
|
|
status: 'ENABLED',
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
}
|
|
|
|
async function seedCdrAndQuality() {
|
|
const startedAt = new Date('2026-01-01T10:00:00.000Z');
|
|
const answeredAt = new Date('2026-01-01T10:00:06.000Z');
|
|
const endedAt = new Date('2026-01-01T10:01:06.000Z');
|
|
|
|
await prisma.rawCdr.upsert({
|
|
where: { id: 'raw_auto_001' },
|
|
update: {
|
|
eventId: 'evt_auto_001',
|
|
callId: 'call_auto_001',
|
|
customerId: 'cus_auto_001',
|
|
customerGatewayId: 'cgw_auto_ip',
|
|
customerGatewayPolicyId: 'cgp_auto_001',
|
|
sourceIp: '10.66.0.10',
|
|
caller: '05510000001',
|
|
callee: '67113800138000',
|
|
rawCallee: '67113800138000',
|
|
businessPrefixId: 'bp_auto_671',
|
|
businessPrefix: '671',
|
|
calleeCityCode: '340100',
|
|
calleeCityName: '合肥市',
|
|
calleeProvinceName: '安徽省',
|
|
calleeOperator: 'MOBILE',
|
|
calleeNumberType: 'MOBILE',
|
|
vendorId: 'ven_auto_001',
|
|
vendorGatewayId: 'vgw_auto_primary',
|
|
lineGroupId: 'llg_auto_001',
|
|
landingCaller: '05510000001',
|
|
landingCallee: '8613800138000',
|
|
startedAt,
|
|
answeredAt,
|
|
endedAt,
|
|
durationSec: 66,
|
|
sipCode: 200,
|
|
hangupReason: 'NORMAL_CLEARING',
|
|
recordingKey: 'seed/call_auto_001.wav',
|
|
configVersion: 1,
|
|
ratingStatus: 'RATED',
|
|
payload: { source: 'test-seed' },
|
|
},
|
|
create: {
|
|
id: 'raw_auto_001',
|
|
eventId: 'evt_auto_001',
|
|
callId: 'call_auto_001',
|
|
customerId: 'cus_auto_001',
|
|
customerGatewayId: 'cgw_auto_ip',
|
|
customerGatewayPolicyId: 'cgp_auto_001',
|
|
sourceIp: '10.66.0.10',
|
|
caller: '05510000001',
|
|
callee: '67113800138000',
|
|
rawCallee: '67113800138000',
|
|
businessPrefixId: 'bp_auto_671',
|
|
businessPrefix: '671',
|
|
calleeCityCode: '340100',
|
|
calleeCityName: '合肥市',
|
|
calleeProvinceName: '安徽省',
|
|
calleeOperator: 'MOBILE',
|
|
calleeNumberType: 'MOBILE',
|
|
vendorId: 'ven_auto_001',
|
|
vendorGatewayId: 'vgw_auto_primary',
|
|
lineGroupId: 'llg_auto_001',
|
|
landingCaller: '05510000001',
|
|
landingCallee: '8613800138000',
|
|
startedAt,
|
|
answeredAt,
|
|
endedAt,
|
|
durationSec: 66,
|
|
sipCode: 200,
|
|
hangupReason: 'NORMAL_CLEARING',
|
|
recordingKey: 'seed/call_auto_001.wav',
|
|
configVersion: 1,
|
|
ratingStatus: 'RATED',
|
|
payload: { source: 'test-seed' },
|
|
},
|
|
});
|
|
|
|
await prisma.ratedCdr.upsert({
|
|
where: { rawCdrId: 'raw_auto_001' },
|
|
update: {
|
|
billSec: 60,
|
|
customerFee: '0.080000',
|
|
vendorCost: '0.035000',
|
|
grossProfit: '0.045000',
|
|
customerRate: { cycleSec: 60, cycleRate: '0.080000' },
|
|
vendorRate: { cycleSec: 60, cycleRate: '0.035000' },
|
|
},
|
|
create: {
|
|
id: 'rated_auto_001',
|
|
rawCdrId: 'raw_auto_001',
|
|
billSec: 60,
|
|
customerFee: '0.080000',
|
|
vendorCost: '0.035000',
|
|
grossProfit: '0.045000',
|
|
customerRate: { cycleSec: 60, cycleRate: '0.080000' },
|
|
vendorRate: { cycleSec: 60, cycleRate: '0.035000' },
|
|
},
|
|
});
|
|
|
|
await prisma.recording.upsert({
|
|
where: { id: 'rec_auto_001' },
|
|
update: {
|
|
rawCdrId: 'raw_auto_001',
|
|
storageKey: 'seed/call_auto_001.wav',
|
|
storagePath: '/recordings/seed/call_auto_001.wav',
|
|
sha256: 'a'.repeat(64),
|
|
bytes: BigInt(55758),
|
|
durationSec: 66,
|
|
status: 'READY',
|
|
movedAt: endedAt,
|
|
},
|
|
create: {
|
|
id: 'rec_auto_001',
|
|
rawCdrId: 'raw_auto_001',
|
|
storageKey: 'seed/call_auto_001.wav',
|
|
storagePath: '/recordings/seed/call_auto_001.wav',
|
|
sha256: 'a'.repeat(64),
|
|
bytes: BigInt(55758),
|
|
durationSec: 66,
|
|
status: 'READY',
|
|
movedAt: endedAt,
|
|
},
|
|
});
|
|
|
|
await prisma.qualitySamplingRule.upsert({
|
|
where: { id: 'qsr_auto_001' },
|
|
update: {
|
|
name: '自动化抽检规则',
|
|
customerId: 'cus_auto_001',
|
|
lineGroupId: 'llg_auto_001',
|
|
ratio: '10.00',
|
|
status: 'ENABLED',
|
|
effectiveAt: startedAt,
|
|
expiresAt: null,
|
|
updatedBy: ACTOR_ID,
|
|
deletedAt: null,
|
|
},
|
|
create: {
|
|
id: 'qsr_auto_001',
|
|
name: '自动化抽检规则',
|
|
customerId: 'cus_auto_001',
|
|
lineGroupId: 'llg_auto_001',
|
|
ratio: '10.00',
|
|
status: 'ENABLED',
|
|
effectiveAt: startedAt,
|
|
createdBy: ACTOR_ID,
|
|
updatedBy: ACTOR_ID,
|
|
},
|
|
});
|
|
|
|
await prisma.qualityReview.upsert({
|
|
where: { id: 'qr_auto_001' },
|
|
update: {
|
|
recordingId: 'rec_auto_001',
|
|
reviewerId: 'usr_test_quality',
|
|
score: 88,
|
|
result: 'PASS',
|
|
issueTags: [],
|
|
notes: '自动化测试质检样本',
|
|
reviewedAt: endedAt,
|
|
},
|
|
create: {
|
|
id: 'qr_auto_001',
|
|
recordingId: 'rec_auto_001',
|
|
reviewerId: 'usr_test_quality',
|
|
score: 88,
|
|
result: 'PASS',
|
|
issueTags: [],
|
|
notes: '自动化测试质检样本',
|
|
reviewedAt: endedAt,
|
|
},
|
|
});
|
|
}
|
|
|
|
async function main() {
|
|
await seedAuth();
|
|
await seedNumberLibrary();
|
|
await seedBusinessData();
|
|
await seedCdrAndQuality();
|
|
|
|
console.log('Test seed completed.');
|
|
console.log(`Login users: ${users.map((user) => user.username).join(', ')}`);
|
|
console.log(`Default password: ${TEST_PASSWORD}`);
|
|
}
|
|
|
|
main()
|
|
.catch((error) => {
|
|
console.error('Test seed failed.', error);
|
|
process.exitCode = 1;
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|