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
+30 -18
View File
@@ -9,6 +9,7 @@ import type { GatewaySubmitResultDto, GatewaySubmitSegmentResultDto, GatewayRece
import { positiveInteger, normalizeReceiptStatus, normalizeCarrier, DEFAULT_DOWNSTREAM_RETRY_DELAY_MS, DEFAULT_DOWNSTREAM_RETRY_MAX_DELAY_MS, DEFAULT_DOWNSTREAM_MAX_RETRIES, DEFAULT_DOWNSTREAM_PENDING_TIMEOUT_HOURS, DEFAULT_RECEIPT_TIMEOUT_HOURS, DEFAULT_GATEWAY_SUBMIT_REQUEUE_STALE_MS, DEFAULT_DOWNSTREAM_MANUAL_REQUEUE_STALE_MS, DEFAULT_UPSTREAM_RECEIPT_INBOX_PROCESSING_STALE_MS, DEFAULT_UPSTREAM_RECEIPT_INBOX_MAX_ATTEMPTS, DEFAULT_UPSTREAM_RECEIPT_INBOX_MAX_AGE_HOURS, gatewaySubmitRequeueKey, isObjectRecord, asDateOrNull, downstreamRetryDelayMs, downstreamAckTimeoutMs, downstreamRetryBaseDelayMs, downstreamRetryMaxDelayMs, downstreamMaxRetries, downstreamPendingTimeoutHours, downstreamControlFailureMessage, normalizeSubmitStatus, downstreamDeliveryAttemptKey, hasRecoveryAuditStateChanged, normalizeRecoveryFailureCategory, aggregateReceiptSegmentState, isSameUpstreamEndpointIdentity, receiptEventKey } from './send-chain.helpers';
import type { SendSubmissionService } from './send-submission.service';
import type { SendCompletionCallbacks, SendCompletionFacade } from './send-completion.service';
import { queueFinalReceiptDeliveries } from './downstream-receipt-targets';
/**
@@ -309,24 +310,32 @@ export class SendReceiptService {
},
});
if (!isStandaloneChannelTest && message.tenantId && message.applicationId) {
await this.facade.queueAndTryDownstreamDelivery({
tenantId: message.tenantId,
applicationId: message.applicationId,
messageRecordId: message.id,
messageId: message.messageId,
deliveryType: 'receipt',
payload: {
messageId: message.messageId,
gatewayMessageId: data.gatewayMessageId,
phoneNumber: message.phoneNumber,
receiptStatus: aggregate.receiptStatus,
rawStatus: aggregate.rawStatus,
errorCode: aggregate.errorCode,
submitSequenceId: message.cmppSubmitSequenceId ? Number(message.cmppSubmitSequenceId) : undefined,
submitGroupMessageId: message.cmppSubmitGroupMessageId ?? undefined,
deliveredAt: aggregate.deliveredAt.toISOString(),
await queueFinalReceiptDeliveries(
this.prisma,
(request) => this.facade.queueAndTryDownstreamDelivery(request),
{
message,
payload: {
messageId: message.messageId,
gatewayMessageId: data.gatewayMessageId,
phoneNumber: message.phoneNumber,
receiptStatus: aggregate.receiptStatus,
rawStatus: aggregate.rawStatus,
errorCode: aggregate.errorCode,
deliveredAt: aggregate.deliveredAt.toISOString(),
},
segmentPayloads: Object.fromEntries(
aggregate.segments
.filter((segment) => segment.receiptStatus)
.map((segment) => [segment.segmentIndex, {
receiptStatus: segment.receiptStatus,
rawStatus: segment.rawStatus,
errorCode: segment.errorCode,
deliveredAt: segment.deliveredAt?.toISOString() ?? aggregate.deliveredAt.toISOString(),
}]),
),
},
});
);
}
if (message.batchTaskId) {
await this.facade.refreshTaskProgress(message.batchTaskId);
@@ -427,7 +436,10 @@ export class SendReceiptService {
: { messageRecordId: message.id, gatewayMessageId: data.gatewayMessageId },
orderBy: { segmentIndex: 'asc' },
});
return aggregateReceiptSegmentState(audits, message.billingUnits, data, deliveredAt);
return {
...aggregateReceiptSegmentState(audits, message.billingUnits, data, deliveredAt),
segments: audits,
};
}
async resolveReceiptMessage(