Skip to content
Merged
15 changes: 12 additions & 3 deletions src/hooks/useBlockDistanceRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ type UseBlockDistanceRequestParams = {

/** Whether the current flow is for any distance request */
isDistanceRequest?: boolean;

/** Whether an existing distance request is being edited */
isEditingExistingDistanceRequest?: boolean;
};

type PolicyRequiringMapOrGPS = {
Expand Down Expand Up @@ -69,7 +72,13 @@ const hasHomeAddressSelector = (privatePersonalDetails: OnyxEntry<PrivatePersona
* When a block occurs, it surfaces the relevant modal and returns true so callers
* can early return.
*/
function useBlockDistanceRequest({policyID, isManualDistanceRequest = false, isOdometerDistanceRequest = false, isDistanceRequest = false}: UseBlockDistanceRequestParams) {
function useBlockDistanceRequest({
policyID,
isManualDistanceRequest = false,
isOdometerDistanceRequest = false,
isDistanceRequest = false,
isEditingExistingDistanceRequest = false,
}: UseBlockDistanceRequestParams) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const {showConfirmModal} = useConfirmModal();
Expand All @@ -79,7 +88,7 @@ function useBlockDistanceRequest({policyID, isManualDistanceRequest = false, isO

const getBlockReason = useCallback(
(policyIDToCheck: string | undefined): BlockDistanceRequestReason | undefined => {
if (!policyIDToCheck || !policiesRequiringMapOrGPS?.[policyIDToCheck]) {
if (!policyIDToCheck || !policiesRequiringMapOrGPS?.[policyIDToCheck] || isEditingExistingDistanceRequest) {
return;
}

Expand All @@ -91,7 +100,7 @@ function useBlockDistanceRequest({policyID, isManualDistanceRequest = false, isO
return 'homeAddressRequired';
}
},
[hasHomeAddress, isDistanceRequest, isManualDistanceRequest, isOdometerDistanceRequest, policiesRequiringMapOrGPS],
[hasHomeAddress, isDistanceRequest, isManualDistanceRequest, isOdometerDistanceRequest, isEditingExistingDistanceRequest, policiesRequiringMapOrGPS],
);

const showBlockModal = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ function DynamicIOURequestStepDistanceManual({
const blockDistanceRequestIfNeeded = useBlockDistanceRequest({
policyID: report?.policyID ?? (shouldAutoReportToDefaultWorkspace ? defaultExpensePolicy?.id : undefined),
isManualDistanceRequest: true,
isEditingExistingDistanceRequest: isEditing,
});

// to make sure the correct distance amount and unit will be shown we use distance unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ function IOURequestStepDistanceOdometer({
const blockDistanceRequestIfNeeded = useBlockDistanceRequest({
policyID: report?.policyID ?? (shouldAutoReportToDefaultWorkspace ? defaultExpensePolicy?.id : undefined),
isOdometerDistanceRequest: true,
isEditingExistingDistanceRequest: isEditing,
});

const mileageRate = DistanceRequestUtils.getRate({
Expand Down
52 changes: 52 additions & 0 deletions tests/unit/TransactionUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,58 @@ describe('TransactionUtils', () => {
},
);

it('does not apply a newly enabled commuter exclusion when a historical manual distance is changed', () => {
const fakePolicy: Policy = {
...createRandomPolicy(0),
commuterExclusions: {
method: CONST.POLICY.COMMUTER_EXCLUSION_METHOD.FIXED_DISTANCE,
fixedDistance: 3,
fixedDistanceUnit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES,
},
customUnits: {
distance: {
name: CONST.CUSTOM_UNITS.NAME_DISTANCE,
customUnitID: 'distance',
rates: {
default: {
customUnitRateID: '1',
currency: CONST.CURRENCY.USD,
rate: 1,
},
},
attributes: {
unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES,
},
},
},
};
const transaction = generateTransaction({
iouRequestType: CONST.IOU.REQUEST_TYPE.DISTANCE_MANUAL,
comment: {
customUnit: {
distanceUnit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES,
quantity: 10,
},
},
currency: CONST.CURRENCY.USD,
});

const updatedTransaction = TransactionUtils.getUpdatedTransaction({
transaction,
isFromExpenseReport: false,
policy: fakePolicy,
transactionChanges: {distance: 20},
personalPolicyOutputCurrency: undefined,
getCurrencyDecimals: getCurrencyDecimalsLocal,
getCurrencySymbol: getCurrencySymbolLocal,
});

expect(updatedTransaction.comment?.customUnit?.quantity).toBe(20);
expect(updatedTransaction.comment?.customUnit?.commuterExclusion).toBeUndefined();
expect(updatedTransaction.comment?.customUnit?.reimbursableDistance).toBeUndefined();
expect(updatedTransaction.modifiedAmount).toBe(20);
});

it('recalculates commuter exclusion data when an alternate route is selected', () => {
const fakePolicy: Policy = {
...createRandomPolicy(0),
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/hooks/useBlockDistanceRequest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,28 @@ describe('useBlockDistanceRequest', () => {
expect(result.current()).toBe(false);
expect(mockShowConfirmModal).not.toHaveBeenCalled();
});

it('does not block editing an existing manual distance request', async () => {
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}policy_forced`, {
id: 'policy_forced',
name: 'Forced workspace',
commuterExclusions: {
method: 'fixedDistance',
fixedDistance: 1,
fixedDistanceUnit: 'mi',
},
});
await waitForBatchedUpdates();

const {result} = renderHook(() =>
useBlockDistanceRequest({
policyID: 'policy_forced',
isManualDistanceRequest: true,
isEditingExistingDistanceRequest: true,
}),
);

expect(result.current()).toBe(false);
expect(mockShowConfirmModal).not.toHaveBeenCalled();
});
});
Loading