Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions src/libs/Violations/ViolationsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,7 @@ const ViolationsUtils = {
const hasCategoryReceiptRequiredViolation = transactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.RECEIPT_REQUIRED && !violation.data);
const hasItemizedReceiptRequiredViolation = transactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED);
const hasOverLimitViolation = transactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.OVER_LIMIT);
// TODO: Uncomment when the OVER_TRIP_LIMIT violation is implemented
// const hasOverTripLimitViolation = transactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.OVER_TRIP_LIMIT);
const hasOverTripLimitViolation = transactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.OVER_TRIP_LIMIT);
const hasCategoryOverLimitViolation = transactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.OVER_CATEGORY_LIMIT);
const hasMissingCommentViolation = transactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.MISSING_COMMENT);
const hasMissingAttendeesViolation = transactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.MISSING_ATTENDEES);
Expand Down Expand Up @@ -463,6 +462,10 @@ const ViolationsUtils = {
isMaxExpenseAmountRuleEnabled(overLimitAmount) &&
expenseAmount > overLimitAmount &&
isControlPolicy;
// Ensure we are comparing amounts in the same currency
const isSameCurrency = updatedTransaction.currency === currency;
const shouldShowOverTripLimitViolation =
canCalculateAmountViolations && !isInvoiceTransaction && TransactionUtils.hasReservationList(updatedTransaction) && isSameCurrency && expenseAmount > -updatedTransaction.amount;
const shouldCategoryShowOverLimitViolation =
canCalculateAmountViolations && !isInvoiceTransaction && typeof categoryOverLimit === 'number' && expenseAmount > categoryOverLimit && isControlPolicy;
const shouldShowMissingComment =
Expand Down Expand Up @@ -573,21 +576,20 @@ const ViolationsUtils = {
});
}

// TODO: Uncomment when the OVER_TRIP_LIMIT violation is implemented
// if (canCalculateAmountViolations && !hasOverTripLimitViolation && Math.abs(updatedTransaction.amount) < Math.abs(amount) && TransactionUtils.hasReservationList(updatedTransaction)) {
// newTransactionViolations.push({
// name: CONST.VIOLATIONS.OVER_TRIP_LIMIT,
// data: {
// formattedLimit: CurrencyUtils.convertAmountToDisplayString(updatedTransaction.amount, updatedTransaction.currency),
// },
// type: CONST.VIOLATION_TYPES.VIOLATION,
// showInReview: true,
// });
// }

// if (canCalculateAmountViolations && hasOverTripLimitViolation && Math.abs(updatedTransaction.amount) >= Math.abs(amount) && TransactionUtils.hasReservationList(updatedTransaction)) {
// newTransactionViolations = reject(newTransactionViolations, {name: CONST.VIOLATIONS.OVER_TRIP_LIMIT});
// }
if (canCalculateAmountViolations && !hasOverTripLimitViolation && shouldShowOverTripLimitViolation) {
newTransactionViolations.push({
name: CONST.VIOLATIONS.OVER_TRIP_LIMIT,
data: {
formattedLimit: CurrencyUtils.convertAmountToDisplayString(-updatedTransaction.amount, updatedTransaction.currency),
},
type: CONST.VIOLATION_TYPES.VIOLATION,
showInReview: true,
});
}

if (canCalculateAmountViolations && hasOverTripLimitViolation && !shouldShowOverTripLimitViolation) {
newTransactionViolations = reject(newTransactionViolations, {name: CONST.VIOLATIONS.OVER_TRIP_LIMIT});
}

if (!hasMissingCommentViolation && shouldShowMissingComment) {
newTransactionViolations.push({
Expand Down
65 changes: 65 additions & 0 deletions tests/unit/ViolationUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ const categoryOverLimitViolation = {
},
};

const overTripLimitViolation = {
name: CONST.VIOLATIONS.OVER_TRIP_LIMIT,
type: CONST.VIOLATION_TYPES.VIOLATION,
showInReview: true,
data: {
formattedLimit: convertAmountToDisplayString(400),
},
};

const categoryMissingCommentViolation = {
name: CONST.VIOLATIONS.MISSING_COMMENT,
type: CONST.VIOLATION_TYPES.VIOLATION,
Expand Down Expand Up @@ -974,6 +983,62 @@ describe('getViolationsOnyxData', () => {
});
});
});

describe('overTripLimit violation', () => {
it('should add overTripLimit violation if the modified transaction amount is over the original transaction amount', () => {
policy.outputCurrency = CONST.CURRENCY.USD;
transaction.amount = -400;
transaction.modifiedAmount = -600;
transaction.receipt = {
reservationList: [
{
start: {date: '2023-07-24'},
end: {date: '2023-07-25'},
type: 'train',
},
],
};
const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false);
expect(result.value).toEqual(expect.arrayContaining([overTripLimitViolation, ...transactionViolations]));
});

it('should not add overTripLimit violation if the modified transaction currency is different from the original transaction currency', () => {
policy.outputCurrency = CONST.CURRENCY.USD;
transaction.amount = -400;
transaction.modifiedAmount = -600;
transaction.currency = CONST.CURRENCY.USD;
transaction.modifiedCurrency = CONST.CURRENCY.GBP;
transaction.receipt = {
reservationList: [
{
start: {date: '2023-07-24'},
end: {date: '2023-07-25'},
type: 'train',
},
],
};
const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false);
expect(result.value).toEqual([]);
});

it('should remove overTripLimit violation if the modified transaction amount is not over the original transaction amount', () => {
policy.outputCurrency = CONST.CURRENCY.USD;
transaction.amount = -400;
transaction.modifiedAmount = -300;
transaction.receipt = {
reservationList: [
{
start: {date: '2023-07-24'},
end: {date: '2023-07-25'},
type: 'train',
},
],
};
const modifiedTransactionViolations = [overTripLimitViolation, ...transactionViolations];
const result = ViolationsUtils.getViolationsOnyxData(transaction, modifiedTransactionViolations, policy, policyTags, policyCategories, false, false);
expect(result.value).toEqual([]);
});
});
});

const getFakeTransaction = (transactionID: string, comment?: Transaction['comment']) => ({
Expand Down
Loading