fix(supply-chain): 基础同步回退视图不存在的 item_type 列引用并修复失败告警原因为空

This commit is contained in:
WuYongJie 2026-10-14 10:38:22 +08:00
parent 83f0fbee86
commit a917949a5e
4 changed files with 13 additions and 7 deletions

View File

@ -29,7 +29,6 @@ export type ProductCatalogWideArchiveRecord = {
archive_spu: string | null
archive_sku: string | null
archive_product_name: string | null
item_type: string | null
archive_image: string | null
archive_designer: string | null
sales_category_name: string | null
@ -254,7 +253,6 @@ class SupplyChainProductArchiveSyncRepositoryClass
archive_spu,
archive_sku,
archive_product_name,
item_type,
archive_image,
archive_designer,
sales_category_name,

View File

@ -41,6 +41,13 @@ describe('product archive sync failure notifications', () => {
expect(notice.content).not.toContain('second line')
})
it('uses the first non-empty line for multi-line driver errors and never renders an empty reason', () => {
const prismaError = new Error('\nInvalid `prisma.$queryRawUnsafe()` invocation:\n\nRaw query failed. Code: `42703`. Message: `column "item_type" does not exist`')
const notice = buildArchiveSyncFailureNotice(ARCHIVE_SYNC_FAILURE_TASKS.development, failedAt, prismaError)
expect(notice.content).toContain('Invalid `prisma.$queryRawUnsafe()` invocation:')
expect(notice.content).not.toMatch(/^原因:\s*$/m)
})
it('sends plain text without action fields to the named bound active recipient', async () => {
const f = fixture()
expect((await f.service.notify(ARCHIVE_SYNC_FAILURE_TASKS.designerBackfill, new Error('boom'))).status).toBe('sent')

View File

@ -43,13 +43,15 @@ function beijingDay(value: Date) {
}
// Notification content is persisted in the delivery log; strip credential-like
// URLs from unexpected driver errors and keep only the first line.
// URLs from unexpected driver errors and keep only the first non-empty line.
function sanitizeSyncFailureReason(error: unknown) {
const message = error instanceof Error && error.message ? error.message : 'UNKNOWN_ERROR'
return message
const firstLine = message
.replace(/\b(postgres(ql)?|mysql|mssql|sqlserver|https?):\/\/\S+/gi, '[credential-url]')
.split('\n')[0]
.slice(0, 200)
.split('\n')
.map(line => line.trim())
.find(line => line.length > 0) ?? 'UNKNOWN_ERROR'
return firstLine.slice(0, 200)
}
export function buildArchiveSyncFailureNotice(task: ArchiveSyncFailureTask, failedAt: Date, error: unknown) {

View File

@ -156,7 +156,6 @@ export function mapProductCatalogWideArchiveSource(
height: decimal(height),
volume: calculateProductArchiveVolumeDecimal(length, width, height),
packType: resolveProductArchivePackageType(text(record.package_set_count)),
productAttribute: text(record.item_type),
productTag: text(record.product_tag),
installDocId: text(record.drawing_id),
spec: text(record.archive_spec),