feat: add number library routing and cdr location support

This commit is contained in:
hectorzhao
2026-06-24 11:39:32 +08:00
parent 5fa1bd35e9
commit 7057fd3c42
63 changed files with 6361 additions and 566 deletions
+7 -10
View File
@@ -4,14 +4,13 @@ import { Prisma } from '@lisglosips/database';
import type { ParsedCdrStreamEvent } from '@lisglosips/redis';
import { calculateCycleCharge } from './billing.js';
import { CdrRatingService, type CdrRatingStore, type CdrRatingTransaction, type CreateCustomerChargeInput, type CreateRatedInput } from './rating.js';
import { CdrRatingService, type CdrRatingStore, type CdrRatingTransaction, type CreateRatedInput } from './rating.js';
class MemoryStore implements CdrRatingStore, CdrRatingTransaction {
rawByEventId = new Map<string, { id: string; eventId: string; ratingStatus: 'UNRATED' | 'RATED' | 'SKIPPED' | 'FAILED' }>();
ratedByRawId = new Map<string, { id: string; rawCdrId: string; customerFee: Prisma.Decimal }>();
vendorGateway = { id: 'vgw_1', vendorId: 'ven_1', billingCycleSec: 6, cycleRate: new Prisma.Decimal('0.012000') };
customer = { id: 'cus_1', balance: new Prisma.Decimal('10.000000') };
charges: CreateCustomerChargeInput[] = [];
async transaction<T>(operation: (tx: CdrRatingTransaction) => Promise<T>): Promise<T> {
return operation(this);
@@ -53,10 +52,6 @@ class MemoryStore implements CdrRatingStore, CdrRatingTransaction {
}
}
async createCustomerCharge(input: CreateCustomerChargeInput): Promise<void> {
this.charges.push(input);
}
async updateCustomerBalance(_customerId: string, balance: Prisma.Decimal): Promise<void> {
this.customer.balance = balance;
}
@@ -78,6 +73,11 @@ function event(overrides: Partial<ParsedCdrStreamEvent> = {}): ParsedCdrStreamEv
source_ip: '100.93.185.30',
caller: '1001',
callee: '13800138000',
callee_city_code: '340100',
callee_city_name: '合肥市',
callee_province_name: '安徽省',
callee_operator: 'MOBILE',
callee_number_type: 'MOBILE',
vendor_id: 'ven_1',
vendor_gateway_id: 'vgw_1',
line_group_id: 'lg_1',
@@ -105,7 +105,7 @@ describe('S23 CDR rating', () => {
expect(charge.amount.toFixed(6)).toBe('0.060000');
});
it('rates a successful CDR and deducts customer balance once', async () => {
it('rates a successful CDR and deducts customer balance once without recharge ledger records', async () => {
const store = new MemoryStore();
const service = new CdrRatingService(store);
@@ -121,8 +121,6 @@ describe('S23 CDR rating', () => {
});
expect(duplicate.outcome).toBe('duplicate');
expect(store.customer.balance.toFixed(6)).toBe('9.940000');
expect(store.charges).toHaveLength(1);
expect(store.charges[0]?.amount.toFixed(6)).toBe('-0.060000');
});
it('skips failed or zero-duration CDRs without balance changes', async () => {
@@ -134,6 +132,5 @@ describe('S23 CDR rating', () => {
expect(result.outcome).toBe('skipped');
expect(result.customerFee).toBe('0.000000');
expect(store.customer.balance.toFixed(6)).toBe('10.000000');
expect(store.charges).toHaveLength(0);
});
});