From 4f99de364a2bd23cef45f2a1ae3b5f5f118d3898 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 23 Jan 2026 17:02:09 -0500 Subject: [PATCH] fix: correct Statuses and Work Types sync to use picklist API Problem: - syncStatuses() and syncWorkTypes() were trying to query /Statuses/query and /WorkTypes/query endpoints which don't exist in Autotask API - This caused 404 errors: 'File or directory not found' - These are picklist values, not queryable entities Solution: - Changed syncStatuses() to use getPicklistValues('Tickets', 'status') - Changed syncWorkTypes() to use getPicklistValues('TimeEntries', 'workType') - Now follows same pattern as syncIssueTypes() and syncSubIssueTypes() - Uses proper picklist API endpoint: /entity/entityInformation/fields This fixes today's sync failures for statuses and work_types entities. --- lib/services/entity-sync.ts | 84 +++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/lib/services/entity-sync.ts b/lib/services/entity-sync.ts index ac38e5c..1d9a691 100644 --- a/lib/services/entity-sync.ts +++ b/lib/services/entity-sync.ts @@ -628,10 +628,48 @@ export class EntitySyncService { } /** - * Sync Statuses (Picklist) + * Sync Statuses (Picklist from Ticket field) */ async syncStatuses(isIncremental: boolean = false): Promise { - return await this.syncEntity(EntityType.STATUSES, isIncremental); + const picklistLogger = this.logger.child({ entityType: EntityType.STATUSES, syncType: 'picklist' }); + const syncStartTime = picklistLogger.start('Picklist sync'); + + try { + // Get status picklist values from Tickets entity + const picklistValues = await this.autotaskClient.getPicklistValues('Tickets', 'status'); + + // Convert picklist to database format + const records = Object.entries(picklistValues).map(([value, label]) => ({ + value: parseInt(value), + label: label, + is_active: true, + sort_order: parseInt(value), + synced_at: new Date(), + })); + + picklistLogger.info('Found picklist values', { recordCount: records.length }); + + // Upsert to database + const tableName = getTableName(EntityType.STATUSES); + const upsertedCount = await postgresClient.bulkUpsert(tableName, records, ['value']); + + const stats: EntitySyncStats = { + recordsAdded: upsertedCount, + recordsUpdated: 0, + recordsDeleted: 0, + }; + + picklistLogger.complete('Picklist sync', syncStartTime, { + recordsAdded: stats.recordsAdded, + recordsUpdated: stats.recordsUpdated, + }); + + return stats; + } catch (error) { + const err = error instanceof Error ? error : new Error(String(error)); + picklistLogger.fail('Picklist sync', syncStartTime, err); + throw error; + } } /** @@ -742,10 +780,48 @@ export class EntitySyncService { } /** - * Sync Work Types (Picklist) + * Sync Work Types (Picklist from TimeEntry field) */ async syncWorkTypes(isIncremental: boolean = false): Promise { - return await this.syncEntity(EntityType.WORK_TYPES, isIncremental); + const picklistLogger = this.logger.child({ entityType: EntityType.WORK_TYPES, syncType: 'picklist' }); + const syncStartTime = picklistLogger.start('Picklist sync'); + + try { + // Get work type picklist values from TimeEntries entity + const picklistValues = await this.autotaskClient.getPicklistValues('TimeEntries', 'workType'); + + // Convert picklist to database format + const records = Object.entries(picklistValues).map(([value, label]) => ({ + value: parseInt(value), + label: label, + is_active: true, + sort_order: parseInt(value), + synced_at: new Date(), + })); + + picklistLogger.info('Found picklist values', { recordCount: records.length }); + + // Upsert to database + const tableName = getTableName(EntityType.WORK_TYPES); + const upsertedCount = await postgresClient.bulkUpsert(tableName, records, ['value']); + + const stats: EntitySyncStats = { + recordsAdded: upsertedCount, + recordsUpdated: 0, + recordsDeleted: 0, + }; + + picklistLogger.complete('Picklist sync', syncStartTime, { + recordsAdded: stats.recordsAdded, + recordsUpdated: stats.recordsUpdated, + }); + + return stats; + } catch (error) { + const err = error instanceof Error ? error : new Error(String(error)); + picklistLogger.fail('Picklist sync', syncStartTime, err); + throw error; + } } /**