fix: time entries incremental sync uses lastModifiedDateTime not dateWorked

Previously the incremental filter compared dateWorked >= lastSyncTime,
meaning edits to existing entries (hours adjusted, notes changed, PTO
blocks entered in advance) were never picked up after initial ingestion.

Switch both the lastModifiedField mapping and buildTimeEntriesFilter to
use lastModifiedDateTime so any created or modified entry is captured
on the next scheduled sync.
This commit is contained in:
lorentz 2026-03-17 23:01:18 -04:00
parent b6c2681a69
commit 7ce06803dc

View file

@ -162,7 +162,7 @@ export function getLastModifiedField(entity: EntityType): string {
[EntityType.CONTRACT_SERVICES]: 'lastModifiedDate', [EntityType.CONTRACT_SERVICES]: 'lastModifiedDate',
[EntityType.AUTOTASK_SERVICES]: 'lastModifiedDate', [EntityType.AUTOTASK_SERVICES]: 'lastModifiedDate',
[EntityType.BILLING_ITEMS]: 'itemDate', [EntityType.BILLING_ITEMS]: 'itemDate',
[EntityType.TIME_ENTRIES]: 'dateWorked', [EntityType.TIME_ENTRIES]: 'lastModifiedDateTime',
[EntityType.TICKET_NOTES]: 'lastActivityDate', [EntityType.TICKET_NOTES]: 'lastActivityDate',
[EntityType.STATUSES]: 'lastModifiedDate', [EntityType.STATUSES]: 'lastModifiedDate',
[EntityType.ISSUE_TYPES]: 'lastModifiedDate', [EntityType.ISSUE_TYPES]: 'lastModifiedDate',
@ -360,18 +360,20 @@ export function buildProjectsFilter(): Array<{ field: string; op: string; value:
* @returns Query filter array for time entries * @returns Query filter array for time entries
*/ */
export function buildTimeEntriesFilter(yearsBack: number = 2): Array<{ field: string; op: string; value: any }> { export function buildTimeEntriesFilter(yearsBack: number = 2): Array<{ field: string; op: string; value: any }> {
// TimeEntries API requires a filter. Use dateWorked to limit the range // TimeEntries API requires a filter. Use lastModifiedDateTime so that edits
// Calculate date from X years ago // to existing entries (e.g. hours changed, notes updated) are picked up even
// if the dateWorked is in the past or future.
// We still bound it by yearsBack to avoid a full scan on first load.
const cutoffDate = new Date(); const cutoffDate = new Date();
const millisecondsPerYear = 365.25 * 24 * 60 * 60 * 1000; const millisecondsPerYear = 365.25 * 24 * 60 * 60 * 1000;
const millisecondsBack = yearsBack * millisecondsPerYear; const millisecondsBack = yearsBack * millisecondsPerYear;
cutoffDate.setTime(cutoffDate.getTime() - millisecondsBack); cutoffDate.setTime(cutoffDate.getTime() - millisecondsBack);
console.log(`TimeEntries filter: dateWorked >= ${cutoffDate.toISOString()} (${yearsBack} years back)`); console.log(`TimeEntries filter: lastModifiedDateTime >= ${cutoffDate.toISOString()} (${yearsBack} years back)`);
return [ return [
{ {
field: 'dateWorked', field: 'lastModifiedDateTime',
op: 'gte', op: 'gte',
value: cutoffDate.toISOString(), value: cutoffDate.toISOString(),
}, },