Files

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();
});