diff --git a/lib/services/entity-sync.ts b/lib/services/entity-sync.ts index bb57f3b..744d0a7 100644 --- a/lib/services/entity-sync.ts +++ b/lib/services/entity-sync.ts @@ -255,10 +255,35 @@ export class EntitySyncService { } } + // Validate company_id foreign keys for tickets (defensive — Task 1 widening + // the Companies filter should make this a near-zero count, but catches the + // truly hard-deleted Autotask company case). + if (entity === EntityType.TICKETS) { + const validCompanyIds = await this.getValidCompanyIds(); + let nullifiedCompanyCount = 0; + const nullifiedCompanySamples: number[] = []; + mappedRecords = mappedRecords.map(ticket => { + if (ticket.company_id && !validCompanyIds.has(ticket.company_id)) { + if (nullifiedCompanySamples.length < 5) { + nullifiedCompanySamples.push(ticket.id); + } + ticket.company_id = null; + nullifiedCompanyCount++; + } + return ticket; + }); + if (nullifiedCompanyCount > 0) { + entityLogger.warn('Nullified ticket company_id for companies missing from mirror', { + nullifiedCount: nullifiedCompanyCount, + sampleTicketIds: nullifiedCompanySamples, + }); + } + } + // Validate resource foreign keys for tickets if (entity === EntityType.TICKETS) { const initialCount = mappedRecords.length; - + // Get all valid resource IDs from database const validResourceIds = await this.getValidResourceIds(); @@ -721,6 +746,17 @@ export class EntitySyncService { return new Set(result.rows.map(row => Number(row.id))); } + /** + * Get all valid company IDs from the database + * Used to validate foreign key references before insert + * @returns Set of valid company IDs + */ + private async getValidCompanyIds(): Promise> { + const query = 'SELECT id FROM companies WHERE is_deleted = false'; + const result = await postgresClient.query<{ id: number }>(query); + return new Set(result.rows.map(row => Number(row.id))); + } + /** * Used to validate foreign key references before insert * @returns Set of valid contact IDs