feat: integrate analytics and fragment receipt improvements

This commit is contained in:
hectorzhao
2026-08-03 15:34:41 +08:00
parent 3357ace7e1
commit 530a65de80
89 changed files with 1964 additions and 324 deletions
@@ -72,8 +72,8 @@ export class AdminSmsConfigController {
}
@Get('enterprise-signatures')
listSignatures(@Query('tenantId') tenantId?: string, @Query('keyword') keyword?: string, @Query('status') status?: string, @Query('enterpriseKeyword') enterpriseKeyword?: string, @Query('applicationKeyword') applicationKeyword?: string, @Query('signatureKeyword') signatureKeyword?: string, @Query('drainageKeyword') drainageKeyword?: string, @Query('page') page?: string, @Query('pageSize') pageSize?: string) {
const query = { tenantId, keyword, status, enterpriseKeyword, applicationKeyword, signatureKeyword, drainageKeyword, page: Number(page), pageSize: Number(pageSize) };
listSignatures(@Query('tenantId') tenantId?: string, @Query('keyword') keyword?: string, @Query('status') status?: string, @Query('enterpriseKeyword') enterpriseKeyword?: string, @Query('applicationKeyword') applicationKeyword?: string, @Query('signatureKeyword') signatureKeyword?: string, @Query('drainageKeyword') drainageKeyword?: string, @Query('submittedAtFrom') submittedAtFrom?: string, @Query('submittedAtTo') submittedAtTo?: string, @Query('page') page?: string, @Query('pageSize') pageSize?: string) {
const query = { tenantId, keyword, status, enterpriseKeyword, applicationKeyword, signatureKeyword, drainageKeyword, submittedAtFrom, submittedAtTo, page: Number(page), pageSize: Number(pageSize) };
return page || pageSize ? this.smsConfig.listSignaturesPage(query) : this.smsConfig.listSignatures(query);
}
@@ -93,8 +93,8 @@ export class AdminSmsConfigController {
}
@Get('drainage-infos')
listDrainageInfos(@Query('tenantId') tenantId?: string, @Query('signatureId') signatureId?: string, @Query('status') status?: string, @Query('keyword') keyword?: string) {
return this.smsConfig.listDrainageInfos({ tenantId, signatureId, status, keyword });
listDrainageInfos(@Query('tenantId') tenantId?: string, @Query('signatureId') signatureId?: string, @Query('status') status?: string, @Query('keyword') keyword?: string, @Query('submittedAtFrom') submittedAtFrom?: string, @Query('submittedAtTo') submittedAtTo?: string) {
return this.smsConfig.listDrainageInfos({ tenantId, signatureId, status, keyword, submittedAtFrom, submittedAtTo });
}
@Post('enterprise-signatures/:id/drainage-infos')
@@ -126,8 +126,8 @@ export class AdminSmsConfigController {
}
@Get('enterprise-templates')
listTemplates(@Query('tenantId') tenantId?: string, @Query('status') status?: string, @Query('keyword') keyword?: string, @Query('enterpriseKeyword') enterpriseKeyword?: string, @Query('applicationKeyword') applicationKeyword?: string, @Query('nameKeyword') nameKeyword?: string, @Query('contentKeyword') contentKeyword?: string, @Query('page') page?: string, @Query('pageSize') pageSize?: string) {
const query = { tenantId, status, keyword, enterpriseKeyword, applicationKeyword, nameKeyword, contentKeyword, page: Number(page), pageSize: Number(pageSize) };
listTemplates(@Query('tenantId') tenantId?: string, @Query('status') status?: string, @Query('keyword') keyword?: string, @Query('enterpriseKeyword') enterpriseKeyword?: string, @Query('applicationKeyword') applicationKeyword?: string, @Query('nameKeyword') nameKeyword?: string, @Query('contentKeyword') contentKeyword?: string, @Query('submittedAtFrom') submittedAtFrom?: string, @Query('submittedAtTo') submittedAtTo?: string, @Query('page') page?: string, @Query('pageSize') pageSize?: string) {
const query = { tenantId, status, keyword, enterpriseKeyword, applicationKeyword, nameKeyword, contentKeyword, submittedAtFrom, submittedAtTo, page: Number(page), pageSize: Number(pageSize) };
return page || pageSize ? this.smsConfig.listTemplatesPage(query) : this.smsConfig.listTemplates(query);
}
+2
View File
@@ -9,6 +9,7 @@ import type { ApplicationListQuery, CreateSignatureMaterialDto, CreateSmsApplica
import { APPLICATION_DISABLE_GRACE_MS, DEFAULT_APPLICATION_DISABLE_SCAN_INTERVAL_MS, DEFAULT_DOWNSTREAM_HEARTBEAT_TIMEOUT_MS, UNRESOLVED_DOWNSTREAM_STATUSES, type TemplateVariableInput, estimateBillingUnits, generateApplicationPassword, getPositiveInteger, getPositiveIntegerEnv, hasReportValue, inferTemplateVariables, isRecord, normalizeApplicationCmppStatus, normalizeApplicationInterfaceType, normalizeApplicationPassword, normalizeApplicationQueuePriority, normalizeCmppAccessNumberConfig, normalizeSmsSignature, parseGatewayDate, reportValueParts, startOfToday, validateAndNormalizeTemplateVariables, validateCompleteSmsSignature } from './sms-config.helpers';
import { SmsReportValidationService } from './report-validation.service';
import { SmsAuditService } from './audit.service';
import { shanghaiDateRange } from '../common/shanghai-date-range';
/** R3 domain service. Kept framework-agnostic and composed behind SmsConfigService. */
export class SmsDrainageService {
@@ -50,6 +51,7 @@ export class SmsDrainageService {
tenantId: query.tenantId,
signatureId: query.signatureId,
auditStatus: query.status && query.status !== 'all' ? query.status : { not: 'deleted' },
submittedAt: shanghaiDateRange(query.submittedAtFrom, query.submittedAtTo),
OR: query.keyword ? [
{ siteName: { contains: query.keyword } },
{ url: { contains: query.keyword } },
+3
View File
@@ -9,6 +9,7 @@ import type { ApplicationListQuery, CreateSignatureMaterialDto, CreateSmsApplica
import { APPLICATION_DISABLE_GRACE_MS, DEFAULT_APPLICATION_DISABLE_SCAN_INTERVAL_MS, DEFAULT_DOWNSTREAM_HEARTBEAT_TIMEOUT_MS, UNRESOLVED_DOWNSTREAM_STATUSES, type TemplateVariableInput, estimateBillingUnits, generateApplicationPassword, getPositiveInteger, getPositiveIntegerEnv, hasReportValue, inferTemplateVariables, isRecord, normalizeApplicationCmppStatus, normalizeApplicationInterfaceType, normalizeApplicationPassword, normalizeApplicationQueuePriority, normalizeCmppAccessNumberConfig, normalizeSmsSignature, parseGatewayDate, reportValueParts, startOfToday, validateAndNormalizeTemplateVariables, validateCompleteSmsSignature } from './sms-config.helpers';
import { SmsReportValidationService } from './report-validation.service';
import { SmsAuditService } from './audit.service';
import { shanghaiDateRange } from '../common/shanghai-date-range';
/** R3 domain service. Kept framework-agnostic and composed behind SmsConfigService. */
export class SmsSignatureService {
@@ -22,6 +23,7 @@ export class SmsSignatureService {
tenant: query.enterpriseKeyword ? { name: { contains: query.enterpriseKeyword } } : undefined,
application: query.applicationKeyword ? { name: { contains: query.applicationKeyword } } : undefined,
name: query.signatureKeyword ? { contains: query.signatureKeyword } : undefined,
updatedAt: shanghaiDateRange(query.submittedAtFrom, query.submittedAtTo),
drainageItems: query.drainageKeyword ? {
some: {
auditStatus: { not: 'deleted' },
@@ -134,6 +136,7 @@ export class SmsSignatureService {
tenant: query.enterpriseKeyword ? { name: { contains: query.enterpriseKeyword } } : undefined,
application: query.applicationKeyword ? { name: { contains: query.applicationKeyword } } : undefined,
name: query.signatureKeyword ? { contains: query.signatureKeyword } : undefined,
updatedAt: shanghaiDateRange(query.submittedAtFrom, query.submittedAtTo),
drainageItems: query.drainageKeyword ? {
some: {
auditStatus: { not: 'deleted' },
@@ -67,6 +67,8 @@ export interface DrainageInfoListQuery {
signatureId?: string;
status?: string;
keyword?: string;
submittedAtFrom?: string;
submittedAtTo?: string;
}
export interface CreateSignatureMaterialDto {
@@ -116,6 +118,8 @@ export interface TemplateListQuery {
applicationKeyword?: string;
nameKeyword?: string;
contentKeyword?: string;
submittedAtFrom?: string;
submittedAtTo?: string;
page?: number;
pageSize?: number;
}
@@ -139,6 +143,8 @@ export interface SignatureListQuery {
applicationKeyword?: string;
signatureKeyword?: string;
drainageKeyword?: string;
submittedAtFrom?: string;
submittedAtTo?: string;
page?: number;
pageSize?: number;
}
@@ -1103,6 +1103,24 @@ describe('SmsConfigService', () => {
expect(prisma.smsSignature.update).not.toHaveBeenCalled();
});
it('applies the audit submission range to signatures, templates and drainage records', async () => {
const prisma = createPrismaMock();
const service = new SmsConfigService(prisma as never);
const query = { submittedAtFrom: '2026-08-01', submittedAtTo: '2026-08-03' };
const expectedRange = {
gte: new Date('2026-08-01T00:00:00+08:00'),
lte: new Date('2026-08-03T23:59:59.999+08:00'),
};
await service.listSignatures(query);
await service.listTemplates(query);
await service.listDrainageInfos(query);
expect(prisma.smsSignature.findMany).toHaveBeenCalledWith(expect.objectContaining({ where: expect.objectContaining({ updatedAt: expectedRange }) }));
expect(prisma.smsTemplate.findMany).toHaveBeenCalledWith(expect.objectContaining({ where: expect.objectContaining({ createdAt: expectedRange }) }));
expect(prisma.smsDrainageInfo.findMany).toHaveBeenCalledWith(expect.objectContaining({ where: expect.objectContaining({ submittedAt: expectedRange }) }));
});
it.each([
'【带 空格】',
' 【外部空格】',
+3
View File
@@ -8,6 +8,7 @@ import { automaticDeliveryMode } from '../open-api/delivery-mode';
import type { ApplicationListQuery, CreateSignatureMaterialDto, CreateSmsApplicationDto, CreateSmsDrainageInfoDto, CreateSmsSignatureDto, CreateSmsSignatureOptions, CreateSmsTemplateDto, CreateSmsTemplateOptions, DrainageInfoListQuery, GatewayDownstreamConnectionEventDto, ReplaceApplicationRouteRulesDto, ReviewDto, SignatureListQuery, StatusChangeDto, TemplateListQuery, UpdateSmsApplicationDto, UpdateSmsDrainageInfoDto, UpdateSmsSignatureDto, UpdateSmsTemplateDto } from './sms-config.contracts';
import { APPLICATION_DISABLE_GRACE_MS, DEFAULT_APPLICATION_DISABLE_SCAN_INTERVAL_MS, DEFAULT_DOWNSTREAM_HEARTBEAT_TIMEOUT_MS, UNRESOLVED_DOWNSTREAM_STATUSES, type TemplateVariableInput, estimateBillingUnits, generateApplicationPassword, getPositiveInteger, getPositiveIntegerEnv, hasReportValue, inferTemplateVariables, isRecord, normalizeApplicationCmppStatus, normalizeApplicationInterfaceType, normalizeApplicationPassword, normalizeApplicationQueuePriority, normalizeCmppAccessNumberConfig, normalizeSmsSignature, parseGatewayDate, reportValueParts, startOfToday, validateAndNormalizeTemplateVariables, validateCompleteSmsSignature } from './sms-config.helpers';
import { SmsAuditService } from './audit.service';
import { shanghaiDateRange } from '../common/shanghai-date-range';
/** R3 domain service. Kept framework-agnostic and composed behind SmsConfigService. */
export class SmsTemplateService {
@@ -22,6 +23,7 @@ export class SmsTemplateService {
application: query.applicationKeyword ? { name: { contains: query.applicationKeyword } } : undefined,
name: query.nameKeyword ? { contains: query.nameKeyword } : undefined,
content: query.contentKeyword ? { contains: query.contentKeyword } : undefined,
createdAt: shanghaiDateRange(query.submittedAtFrom, query.submittedAtTo),
OR: query.keyword ? [
{ name: { contains: query.keyword } },
{ content: { contains: query.keyword } },
@@ -49,6 +51,7 @@ export class SmsTemplateService {
application: query.applicationKeyword ? { name: { contains: query.applicationKeyword } } : undefined,
name: query.nameKeyword ? { contains: query.nameKeyword } : undefined,
content: query.contentKeyword ? { contains: query.contentKeyword } : undefined,
createdAt: shanghaiDateRange(query.submittedAtFrom, query.submittedAtTo),
OR: query.keyword ? [
{ name: { contains: query.keyword } },
{ content: { contains: query.keyword } },