From d6f86261e7db1bf16563a1a0324e115b2745bb70 Mon Sep 17 00:00:00 2001 From: shahid Date: Tue, 4 Feb 2025 09:26:51 +0530 Subject: [PATCH 1/4] Correct per diem time calculation for same-day expenses --- src/libs/PerDiemRequestUtils.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libs/PerDiemRequestUtils.ts b/src/libs/PerDiemRequestUtils.ts index 5c5b3bbabed4..375a29c8c6d3 100644 --- a/src/libs/PerDiemRequestUtils.ts +++ b/src/libs/PerDiemRequestUtils.ts @@ -258,6 +258,19 @@ function getTimeDifferenceIntervals(transaction: OnyxEntry) { const customUnitRateDate = transaction?.comment?.customUnit?.attributes?.dates ?? {start: '', end: ''}; const startDate = new Date(customUnitRateDate.start); const endDate = new Date(customUnitRateDate.end); + // Check if start and end dates are on the same day + const isSameDay = startOfDay(startDate).getTime() === startOfDay(endDate).getTime(); + + if (isSameDay) { + // If same day, just calculate the direct hour difference + const hourDiff = differenceInMinutes(endDate, startDate) / 60; + return { + firstDay: hourDiff, + tripDays: 0, + lastDay: undefined, + }; + } + const firstDayDiff = differenceInMinutes(startOfDay(addDays(startDate, 1)), startDate); const tripDaysDiff = differenceInDays(startOfDay(endDate), startOfDay(addDays(startDate, 1))); const lastDayDiff = differenceInMinutes(endDate, startOfDay(endDate)); From b01329013203edbec6d483c879de5a2895f43695 Mon Sep 17 00:00:00 2001 From: shahid Date: Tue, 4 Feb 2025 13:08:48 +0530 Subject: [PATCH 2/4] use isSameDay for finding the same day --- src/libs/PerDiemRequestUtils.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/libs/PerDiemRequestUtils.ts b/src/libs/PerDiemRequestUtils.ts index 375a29c8c6d3..71a950998980 100644 --- a/src/libs/PerDiemRequestUtils.ts +++ b/src/libs/PerDiemRequestUtils.ts @@ -1,4 +1,4 @@ -import {addDays, differenceInDays, differenceInMinutes, format, startOfDay} from 'date-fns'; +import {addDays, differenceInDays, differenceInMinutes, format, isSameDay, startOfDay} from 'date-fns'; import lodashSortBy from 'lodash/sortBy'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; @@ -258,11 +258,8 @@ function getTimeDifferenceIntervals(transaction: OnyxEntry) { const customUnitRateDate = transaction?.comment?.customUnit?.attributes?.dates ?? {start: '', end: ''}; const startDate = new Date(customUnitRateDate.start); const endDate = new Date(customUnitRateDate.end); - // Check if start and end dates are on the same day - const isSameDay = startOfDay(startDate).getTime() === startOfDay(endDate).getTime(); - if (isSameDay) { - // If same day, just calculate the direct hour difference + if (isSameDay(startDate, endDate)) { const hourDiff = differenceInMinutes(endDate, startDate) / 60; return { firstDay: hourDiff, From 18ddc74c6da756c02d8ab74582a4a2ef25138e2b Mon Sep 17 00:00:00 2001 From: shahid Date: Tue, 4 Feb 2025 14:19:20 +0530 Subject: [PATCH 3/4] add unit test for getTimeDifferenceIntervals --- tests/unit/getTimeDifferenceIntervalsTest.ts | 82 ++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tests/unit/getTimeDifferenceIntervalsTest.ts diff --git a/tests/unit/getTimeDifferenceIntervalsTest.ts b/tests/unit/getTimeDifferenceIntervalsTest.ts new file mode 100644 index 000000000000..e7e7adc3dc26 --- /dev/null +++ b/tests/unit/getTimeDifferenceIntervalsTest.ts @@ -0,0 +1,82 @@ +import {addDays, differenceInDays, differenceInMinutes, isSameDay, startOfDay} from 'date-fns'; +import type {OnyxEntry} from 'react-native-onyx'; +import {getTimeDifferenceIntervals} from '@libs/PerDiemRequestUtils'; +import type Transaction from '@src/types/onyx/Transaction'; + +describe('getTimeDifferenceIntervals', () => { + const createMockTransaction = (startDate: string, endDate: string): OnyxEntry => + ({ + comment: { + customUnit: { + attributes: { + dates: { + start: startDate, + end: endDate, + }, + }, + }, + }, + } as OnyxEntry); + + it('calculates hours for same-day transactions', () => { + // Given a transaction that starts and ends on the same day + const startDate = '2024-03-20T09:00:00Z'; + const endDate = '2024-03-20T17:00:00Z'; + const transaction = createMockTransaction(startDate, endDate); + + const result = getTimeDifferenceIntervals(transaction); + + // When we calculate the time difference intervals + const expectedHours = differenceInMinutes(new Date(endDate), new Date(startDate)) / 60; + + // Then we should get the correct number of hours for a single day, there should be no trip days and no last day + expect(result).toEqual({ + firstDay: expectedHours, + tripDays: 0, + lastDay: undefined, + }); + }); + + it('calculates hours spanning two days', () => { + // Given a transaction that spans across two days + const startDate = '2024-03-20T14:00:00Z'; + const endDate = '2024-03-21T16:00:00Z'; + const transaction = createMockTransaction(startDate, endDate); + + const result = getTimeDifferenceIntervals(transaction); + + // When we calculate the time difference intervals + const startDateTime = new Date(startDate); + const firstDayDiff = differenceInMinutes(startOfDay(addDays(startDateTime, 1)), startDateTime); + const lastDayDiff = differenceInMinutes(new Date(endDate), startOfDay(new Date(endDate))); + + // Then we should get the correct split of hours, there should be no trip days + expect(result).toEqual({ + firstDay: firstDayDiff / 60, + tripDays: 0, + lastDay: lastDayDiff / 60, + }); + }); + + it('calculates hours for multi-day trips', () => { + // Given a transaction that spans multiple days + const startDate = '2024-03-20T16:00:00Z'; + const endDate = '2024-03-23T14:00:00Z'; + const transaction = createMockTransaction(startDate, endDate); + + const result = getTimeDifferenceIntervals(transaction); + + // When we calculate the time difference intervals + const startDateTime = new Date(startDate); + const firstDayDiff = differenceInMinutes(startOfDay(addDays(startDateTime, 1)), startDateTime); + const tripDaysDiff = differenceInDays(startOfDay(new Date(endDate)), startOfDay(addDays(startDateTime, 1))); + const lastDayDiff = differenceInMinutes(new Date(endDate), startOfDay(new Date(endDate))); + + // Then we should get the correct hours split, there should be trip days and last day + expect(result).toEqual({ + firstDay: firstDayDiff / 60, + tripDays: tripDaysDiff, + lastDay: lastDayDiff / 60, + }); + }); +}); From 40f1c51e6b9175ac1d8e876699f77d380587e08f Mon Sep 17 00:00:00 2001 From: shahid Date: Tue, 4 Feb 2025 14:27:14 +0530 Subject: [PATCH 4/4] fix lint --- tests/unit/getTimeDifferenceIntervalsTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/getTimeDifferenceIntervalsTest.ts b/tests/unit/getTimeDifferenceIntervalsTest.ts index e7e7adc3dc26..72dce3bb2058 100644 --- a/tests/unit/getTimeDifferenceIntervalsTest.ts +++ b/tests/unit/getTimeDifferenceIntervalsTest.ts @@ -1,4 +1,4 @@ -import {addDays, differenceInDays, differenceInMinutes, isSameDay, startOfDay} from 'date-fns'; +import {addDays, differenceInDays, differenceInMinutes, startOfDay} from 'date-fns'; import type {OnyxEntry} from 'react-native-onyx'; import {getTimeDifferenceIntervals} from '@libs/PerDiemRequestUtils'; import type Transaction from '@src/types/onyx/Transaction';