feat: add reconciliation and quality reporting
This commit is contained in:
+79
-3
@@ -581,7 +581,16 @@ export type ApplicationReportField = {
|
||||
required: boolean;
|
||||
description?: string | null;
|
||||
reportTypes: string[];
|
||||
channels: Array<{ id: string; code: string; name: string; groupId: string; groupName: string; required: boolean; reportType: 'signature' | 'drainage' | 'both' }>;
|
||||
commonReportTypes?: Array<'signature' | 'drainage'>;
|
||||
channels: Array<{ id: string; code: string; name: string; groupId: string; groupName: string; required: boolean; reportType: 'signature' | 'drainage' | 'both'; source?: 'common' | 'channel' | 'both' }>;
|
||||
};
|
||||
|
||||
export type CommonReportField = DictionaryItem & {
|
||||
drainageFieldId: string;
|
||||
reportType: 'signature' | 'drainage';
|
||||
required: boolean;
|
||||
sortOrder: number;
|
||||
drainageField: DictionaryItem & { code?: string; name?: string; fieldType?: string; description?: string | null };
|
||||
};
|
||||
|
||||
export type ReportTask = DictionaryItem & {
|
||||
@@ -696,6 +705,59 @@ export type PagedResponse<T> = {
|
||||
pageSize: number;
|
||||
};
|
||||
|
||||
export type DailyReconciliationReport = {
|
||||
id: string;
|
||||
reportDate: string;
|
||||
tenantId: string;
|
||||
tenantName: string;
|
||||
applicationId: string;
|
||||
applicationName: string;
|
||||
sentUnits: number;
|
||||
successUnits: number;
|
||||
generatedAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type DailyProfitReport = {
|
||||
id: string;
|
||||
reportDate: string;
|
||||
dimensionType: 'application' | 'channel';
|
||||
dimensionId: string;
|
||||
dimensionName: string;
|
||||
tenantId?: string | null;
|
||||
tenantName?: string | null;
|
||||
applicationId?: string | null;
|
||||
channelId?: string | null;
|
||||
sentUnits: number;
|
||||
successUnits: number;
|
||||
revenueCents: number;
|
||||
costCents: number;
|
||||
profitCents: number;
|
||||
profitRateBps: number;
|
||||
generatedAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type DailyQualityReport = {
|
||||
id: string;
|
||||
reportDate: string;
|
||||
dimensionType: 'application' | 'channel' | 'signature' | 'drainage';
|
||||
dimensionId: string;
|
||||
dimensionName: string;
|
||||
tenantId?: string | null;
|
||||
tenantName?: string | null;
|
||||
applicationId?: string | null;
|
||||
channelId?: string | null;
|
||||
signatureId?: string | null;
|
||||
drainageInfoId?: string | null;
|
||||
sentUnits: number;
|
||||
successUnits: number;
|
||||
successRateBps: number;
|
||||
avgArrivalMs?: number | null;
|
||||
generatedAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type CursorPage<T> = {
|
||||
items: T[];
|
||||
pageSize: number;
|
||||
@@ -979,9 +1041,17 @@ export const adminApi = {
|
||||
request<ApplicationConnectionsResponse>(`/admin/enterprise-applications/${applicationId}/connections`),
|
||||
listApplicationReportFields: (applicationId: string, reportType?: 'signature' | 'drainage') =>
|
||||
request<ApplicationReportField[]>(withQuery(`/admin/enterprise-applications/${applicationId}/report-fields`, { reportType })),
|
||||
listCommonApplicationReportFields: (reportType: 'signature' | 'drainage') =>
|
||||
request<ApplicationReportField[]>(withQuery('/admin/report-fields/common', { reportType })),
|
||||
getApplicationCmppParams: (applicationId: string) =>
|
||||
request<ApplicationCmppParams>(`/admin/enterprise-applications/${applicationId}/cmpp-params`),
|
||||
listChannels: () => request<AdminChannel[]>('/admin/channels'),
|
||||
listReconciliationReports: (query: { dateFrom?: string; dateTo?: string; tenantId?: string; applicationId?: string; page?: number; pageSize?: number } = {}) =>
|
||||
request<PagedResponse<DailyReconciliationReport>>(withQuery('/admin/reports/reconciliation', query)),
|
||||
listProfitReports: (query: { dateFrom?: string; dateTo?: string; dimensionType?: 'application' | 'channel'; tenantId?: string; applicationId?: string; channelId?: string; page?: number; pageSize?: number } = {}) =>
|
||||
request<PagedResponse<DailyProfitReport> & { dimensionType: 'application' | 'channel' }>(withQuery('/admin/reports/profit', query)),
|
||||
listQualityReports: (query: { dateFrom?: string; dateTo?: string; dimensionType?: 'application' | 'channel' | 'signature' | 'drainage'; tenantId?: string; applicationId?: string; channelId?: string; page?: number; pageSize?: number } = {}) =>
|
||||
request<PagedResponse<DailyQualityReport> & { dimensionType: DailyQualityReport['dimensionType'] }>(withQuery('/admin/reports/quality', query)),
|
||||
createChannel: (body: Partial<AdminChannel> & { passwordCipher?: string; desiredConnections?: number; windowSize?: number }) =>
|
||||
request<AdminChannel>('/admin/channels', { method: 'POST', body: JSON.stringify(body) }),
|
||||
updateChannel: (id: string, body: Partial<AdminChannel> & { passwordCipher?: string; desiredConnections?: number; windowSize?: number }) =>
|
||||
@@ -1150,6 +1220,10 @@ export const adminApi = {
|
||||
createDrainageField: (body: { code: string; name: string; fieldType: 'string' | 'image' | 'file'; required?: boolean; status?: string; description?: string }) =>
|
||||
request<DictionaryItem>('/admin/dictionaries/drainage-fields', { method: 'POST', body: JSON.stringify(body) }),
|
||||
deleteDrainageField: (id: string) => request<DictionaryItem>(`/admin/dictionaries/drainage-fields/${id}`, { method: 'DELETE' }),
|
||||
listCommonReportFields: () => request<CommonReportField[]>('/admin/dictionaries/common-report-fields'),
|
||||
createCommonReportField: (body: { drainageFieldId: string; reportType: 'signature' | 'drainage'; required: boolean; sortOrder?: number }) =>
|
||||
request<CommonReportField>('/admin/dictionaries/common-report-fields', { method: 'POST', body: JSON.stringify(body) }),
|
||||
deleteCommonReportField: (id: string) => request<CommonReportField>(`/admin/dictionaries/common-report-fields/${id}`, { method: 'DELETE' }),
|
||||
uploadFileObject: async (file: File, body: { purpose: string; prefix?: string }, tenantId?: string) => {
|
||||
const form = new FormData();
|
||||
form.set('file', file);
|
||||
@@ -1215,8 +1289,10 @@ export const clientApi = {
|
||||
request<ClientSmsApplication[]>('/client/applications', { tenantId }),
|
||||
getApplicationCmppParams: (applicationId: string, tenantId = getSessionTenantId() ?? DEFAULT_CLIENT_TENANT_ID) =>
|
||||
request<ApplicationCmppParams>(`/client/applications/${applicationId}/cmpp-params`, { tenantId }),
|
||||
listApplicationReportFields: (applicationId: string, tenantId = getSessionTenantId() ?? DEFAULT_CLIENT_TENANT_ID) =>
|
||||
request<ApplicationReportField[]>(`/client/applications/${applicationId}/report-fields`, { tenantId }),
|
||||
listApplicationReportFields: (applicationId: string, reportType: 'signature' | 'drainage' = 'drainage', tenantId = getSessionTenantId() ?? DEFAULT_CLIENT_TENANT_ID) =>
|
||||
request<ApplicationReportField[]>(withQuery(`/client/applications/${applicationId}/report-fields`, { reportType }), { tenantId }),
|
||||
listCommonApplicationReportFields: (reportType: 'signature' | 'drainage', tenantId = getSessionTenantId() ?? DEFAULT_CLIENT_TENANT_ID) =>
|
||||
request<ApplicationReportField[]>(withQuery('/client/report-fields/common', { reportType }), { tenantId }),
|
||||
listSignatures: (tenantId = getSessionTenantId() ?? DEFAULT_CLIENT_TENANT_ID) =>
|
||||
request<ClientSmsSignature[]>('/client/signatures', { tenantId }),
|
||||
createSignature: (body: { tenantId?: string; applicationId?: string; name: string; purpose?: string; drainageInfo?: Record<string, unknown> }, tenantId = getSessionTenantId() ?? DEFAULT_CLIENT_TENANT_ID) =>
|
||||
|
||||
Reference in New Issue
Block a user