Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle customUnitOutOfPolicy violation #47136

Merged
merged 23 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6b4cb7a
Handle customUnitOutOfPolicy violation
paultsimura Aug 9, 2024
50c9050
Merge branch 'refs/heads/main' into feat/46753-p2p-violation
paultsimura Aug 10, 2024
927879b
Lint
paultsimura Aug 10, 2024
cc472a2
Lint
paultsimura Aug 10, 2024
742d1a3
Revert accidental change
paultsimura Aug 11, 2024
6e8f62b
Merge branch 'refs/heads/main' into feat/46753-p2p-violation
paultsimura Aug 14, 2024
8ad415a
Merge branch 'main' into feat/46753-p2p-violation
neil-marcellini Sep 6, 2024
ce53514
WIP fix optimistic rate update
neil-marcellini Sep 6, 2024
cc97528
Frontend only modifiedCustomUnitRateID is unnecessary
neil-marcellini Sep 8, 2024
6445f4d
Fix optimistic amount update when rate changes
neil-marcellini Sep 8, 2024
02e5e69
WIP fix optimistic rate modified expense message
neil-marcellini Sep 9, 2024
517d0ba
Fix optimistic modified rate in modified expense message
neil-marcellini Sep 9, 2024
af551f3
WIP modified distance or rate message matching backend
neil-marcellini Sep 9, 2024
32c73a9
Implement updated the distance translations
neil-marcellini Sep 9, 2024
f994254
The field is the merchant specific to distance expenses
neil-marcellini Sep 9, 2024
967460b
Make sure translatedChangedField is lowercase
neil-marcellini Sep 9, 2024
929e687
Fix matching currency symbols in distance merchant
neil-marcellini Sep 9, 2024
3b944bf
Fix style and clean up
neil-marcellini Sep 10, 2024
1f4c348
Clarify that changedField must be translated
neil-marcellini Sep 10, 2024
dd14a19
Move distance merchant regex to CONST
neil-marcellini Sep 10, 2024
d454c2f
Small cleanup and test distance rate message
neil-marcellini Sep 10, 2024
0461782
Test modified expense for distance changed
neil-marcellini Sep 10, 2024
1000dba
Merge branch 'main' into feat/46753-p2p-violation
neil-marcellini Sep 12, 2024
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
13 changes: 1 addition & 12 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2544,10 +2544,8 @@ const CONST = {
ATTACHMENT_ID: /chat-attachments\/(\d+)/,
HAS_COLON_ONLY_AT_THE_BEGINNING: /^:[^:]+$/,
HAS_AT_MOST_TWO_AT_SIGNS: /^@[^@]*@?[^@]*$/,

EMPTY_COMMENT: /^(\s)*$/,
SPECIAL_CHAR: /[,/?"{}[\]()&^%;`$=#<>!*]/g,

FIRST_SPACE: /.+?(?=\s)/,

get SPECIAL_CHAR_OR_EMOJI() {
Expand All @@ -2565,33 +2563,24 @@ const CONST = {
},

MERGED_ACCOUNT_PREFIX: /^(MERGED_\d+@)/,

ROUTES: {
VALIDATE_LOGIN: /\/v($|(\/\/*))/,
UNLINK_LOGIN: /\/u($|(\/\/*))/,
REDUNDANT_SLASHES: /(\/{2,})|(\/$)/g,
},

TIME_STARTS_01: /^01:\d{2} [AP]M$/,
TIME_FORMAT: /^\d{2}:\d{2} [AP]M$/,
DATE_TIME_FORMAT: /^\d{2}-\d{2} \d{2}:\d{2} [AP]M$/,
ILLEGAL_FILENAME_CHARACTERS: /\/|<|>|\*|"|:|\?|\\|\|/g,

ENCODE_PERCENT_CHARACTER: /%(25)+/g,

INVISIBLE_CHARACTERS_GROUPS: /[\p{C}\p{Z}]/gu,

OTHER_INVISIBLE_CHARACTERS: /[\u3164]/g,

REPORT_FIELD_TITLE: /{report:([a-zA-Z]+)}/g,

PATH_WITHOUT_POLICY_ID: /\/w\/[a-zA-Z0-9]+(\/|$)/,

POLICY_ID_FROM_PATH: /\/w\/([a-zA-Z0-9]+)(\/|$)/,

SHORT_MENTION: new RegExp(`@[\\w\\-\\+\\'#@]+(?:\\.[\\w\\-\\'\\+]+)*(?![^\`]*\`)`, 'gim'),

REPORT_ID_FROM_PATH: /\/r\/(\d+)/,
DISTANCE_MERCHANT: /^[0-9.]+ \w+ @ (-|-\()?[^0-9.\s]{1,3} ?[0-9.]+\)? \/ \w+$/,

get EXPENSIFY_POLICY_DOMAIN_NAME() {
return new RegExp(`${EXPENSIFY_POLICY_DOMAIN}([a-zA-Z0-9]+)\\${EXPENSIFY_POLICY_DOMAIN_EXTENSION}`);
Expand Down
2 changes: 2 additions & 0 deletions src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,8 @@ function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = fals
onPress={() =>
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE_RATE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1'))
}
brickRoadIndicator={getErrorForField('customUnitRateID') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
errorText={getErrorForField('customUnitRateID')}
/>
</OfflineWithFeedback>
</>
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useViolations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {TransactionViolation, ViolationName} from '@src/types/onyx';
/**
* Names of Fields where violations can occur.
*/
type ViolationField = 'amount' | 'billable' | 'category' | 'comment' | 'date' | 'merchant' | 'receipt' | 'tag' | 'tax' | 'none';
type ViolationField = 'amount' | 'billable' | 'category' | 'comment' | 'date' | 'merchant' | 'receipt' | 'tag' | 'tax' | 'customUnitRateID' | 'none';

/**
* Map from Violation Names to the field where that violation can occur.
Expand All @@ -17,7 +17,7 @@ const violationFields: Record<ViolationName, ViolationField> = {
cashExpenseWithNoReceipt: 'receipt',
categoryOutOfPolicy: 'category',
conversionSurcharge: 'amount',
customUnitOutOfPolicy: 'merchant',
customUnitOutOfPolicy: 'customUnitRateID',
duplicatedTransaction: 'merchant',
fieldRequired: 'merchant',
futureDate: 'date',
Expand Down
13 changes: 7 additions & 6 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ import type {
ResolutionConstraintsParams,
RoomNameReservedErrorParams,
RoomRenamedToParams,
SetTheDistanceParams,
SetTheDistanceMerchantParams,
SetTheRequestParams,
SettledAfterAddedBankAccountParams,
SettleExpensifyCardParams,
Expand All @@ -98,7 +98,7 @@ import type {
UnapprovedParams,
UnshareParams,
UntilTimeParams,
UpdatedTheDistanceParams,
UpdatedTheDistanceMerchantParams,
UpdatedTheRequestParams,
UsePlusButtonParams,
UserIsAlreadyMemberParams,
Expand Down Expand Up @@ -841,11 +841,12 @@ export default {
pendingConversionMessage: "Total will update when you're back online",
changedTheExpense: 'changed the expense',
setTheRequest: ({valueName, newValueToDisplay}: SetTheRequestParams) => `the ${valueName} to ${newValueToDisplay}`,
setTheDistance: ({newDistanceToDisplay, newAmountToDisplay}: SetTheDistanceParams) => `set the distance to ${newDistanceToDisplay}, which set the amount to ${newAmountToDisplay}`,
setTheDistanceMerchant: ({translatedChangedField, newMerchant, newAmountToDisplay}: SetTheDistanceMerchantParams) =>
`set the ${translatedChangedField} to ${newMerchant}, which set the amount to ${newAmountToDisplay}`,
removedTheRequest: ({valueName, oldValueToDisplay}: RemovedTheRequestParams) => `the ${valueName} (previously ${oldValueToDisplay})`,
updatedTheRequest: ({valueName, newValueToDisplay, oldValueToDisplay}: UpdatedTheRequestParams) => `the ${valueName} to ${newValueToDisplay} (previously ${oldValueToDisplay})`,
updatedTheDistance: ({newDistanceToDisplay, oldDistanceToDisplay, newAmountToDisplay, oldAmountToDisplay}: UpdatedTheDistanceParams) =>
`changed the distance to ${newDistanceToDisplay} (previously ${oldDistanceToDisplay}), which updated the amount to ${newAmountToDisplay} (previously ${oldAmountToDisplay})`,
updatedTheDistanceMerchant: ({translatedChangedField, newMerchant, oldMerchant, newAmountToDisplay, oldAmountToDisplay}: UpdatedTheDistanceMerchantParams) =>
`changed the ${translatedChangedField} to ${newMerchant} (previously ${oldMerchant}), which updated the amount to ${newAmountToDisplay} (previously ${oldAmountToDisplay})`,
threadExpenseReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `${formattedAmount} ${comment ? `for ${comment}` : 'expense'}`,
threadTrackReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `Tracking ${formattedAmount} ${comment ? `for ${comment}` : ''}`,
threadPaySomeoneReportName: ({formattedAmount, comment}: ThreadSentMoneyReportNameParams) => `${formattedAmount} sent${comment ? ` for ${comment}` : ''}`,
Expand Down Expand Up @@ -4369,7 +4370,7 @@ export default {
cashExpenseWithNoReceipt: ({formattedLimit}: ViolationsCashExpenseWithNoReceiptParams) => `Receipt required${formattedLimit ? ` over ${formattedLimit}` : ''}`,
categoryOutOfPolicy: 'Category no longer valid',
conversionSurcharge: ({surcharge}: ViolationsConversionSurchargeParams) => `Applied ${surcharge}% conversion surcharge`,
customUnitOutOfPolicy: 'Unit no longer valid',
customUnitOutOfPolicy: 'Rate not valid for this workspace',
duplicatedTransaction: 'Duplicate',
fieldRequired: 'Report fields are required',
futureDate: 'Future date not allowed',
Expand Down
14 changes: 7 additions & 7 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ import type {
ResolutionConstraintsParams,
RoomNameReservedErrorParams,
RoomRenamedToParams,
SetTheDistanceParams,
SetTheDistanceMerchantParams,
SetTheRequestParams,
SettledAfterAddedBankAccountParams,
SettleExpensifyCardParams,
Expand All @@ -96,7 +96,7 @@ import type {
UnapprovedParams,
UnshareParams,
UntilTimeParams,
UpdatedTheDistanceParams,
UpdatedTheDistanceMerchantParams,
UpdatedTheRequestParams,
UsePlusButtonParams,
UserIsAlreadyMemberParams,
Expand Down Expand Up @@ -834,13 +834,13 @@ export default {
pendingConversionMessage: 'El total se actualizará cuando estés online',
changedTheExpense: 'cambió el gasto',
setTheRequest: ({valueName, newValueToDisplay}: SetTheRequestParams) => `${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} a ${newValueToDisplay}`,
setTheDistance: ({newDistanceToDisplay, newAmountToDisplay}: SetTheDistanceParams) =>
`estableció la distancia a ${newDistanceToDisplay}, lo que estableció el importe a ${newAmountToDisplay}`,
setTheDistanceMerchant: ({translatedChangedField, newMerchant, newAmountToDisplay}: SetTheDistanceMerchantParams) =>
`estableció la ${translatedChangedField} a ${newMerchant}, lo que estableció el importe a ${newAmountToDisplay}`,
removedTheRequest: ({valueName, oldValueToDisplay}: RemovedTheRequestParams) => `${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} (previamente ${oldValueToDisplay})`,
updatedTheRequest: ({valueName, newValueToDisplay, oldValueToDisplay}: UpdatedTheRequestParams) =>
`${valueName === 'comerciante' || valueName === 'importe' || valueName === 'gasto' ? 'el' : 'la'} ${valueName} a ${newValueToDisplay} (previamente ${oldValueToDisplay})`,
updatedTheDistance: ({newDistanceToDisplay, oldDistanceToDisplay, newAmountToDisplay, oldAmountToDisplay}: UpdatedTheDistanceParams) =>
`cambió la distancia a ${newDistanceToDisplay} (previamente ${oldDistanceToDisplay}), lo que cambió el importe a ${newAmountToDisplay} (previamente ${oldAmountToDisplay})`,
updatedTheDistanceMerchant: ({translatedChangedField, newMerchant, oldMerchant, newAmountToDisplay, oldAmountToDisplay}: UpdatedTheDistanceMerchantParams) =>
`cambió la ${translatedChangedField} a ${newMerchant} (previamente ${oldMerchant}), lo que cambió el importe a ${newAmountToDisplay} (previamente ${oldAmountToDisplay})`,
threadExpenseReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `${comment ? `${formattedAmount} para ${comment}` : `Gasto de ${formattedAmount}`}`,
threadTrackReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `Seguimiento ${formattedAmount} ${comment ? `para ${comment}` : ''}`,
threadPaySomeoneReportName: ({formattedAmount, comment}: ThreadSentMoneyReportNameParams) => `${formattedAmount} enviado${comment ? ` para ${comment}` : ''}`,
Expand Down Expand Up @@ -4883,7 +4883,7 @@ export default {
cashExpenseWithNoReceipt: ({formattedLimit}: ViolationsCashExpenseWithNoReceiptParams) => `Recibo obligatorio para cantidades mayores de ${formattedLimit}`,
categoryOutOfPolicy: 'La categoría ya no es válida',
conversionSurcharge: ({surcharge}: ViolationsConversionSurchargeParams = {}) => `${surcharge}% de recargo aplicado`,
customUnitOutOfPolicy: 'La unidad ya no es válida',
customUnitOutOfPolicy: 'Tasa inválida para este espacio de trabajo',
duplicatedTransaction: 'Duplicado',
fieldRequired: 'Los campos del informe son obligatorios',
futureDate: 'Fecha futura no permitida',
Expand Down
8 changes: 4 additions & 4 deletions src/languages/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,13 @@ type ParentNavigationSummaryParams = {reportName?: string; workspaceName?: strin

type SetTheRequestParams = {valueName: string; newValueToDisplay: string};

type SetTheDistanceParams = {newDistanceToDisplay: string; newAmountToDisplay: string};
type SetTheDistanceMerchantParams = {translatedChangedField: string; newMerchant: string; newAmountToDisplay: string};

type RemovedTheRequestParams = {valueName: string; oldValueToDisplay: string};

type UpdatedTheRequestParams = {valueName: string; newValueToDisplay: string; oldValueToDisplay: string};

type UpdatedTheDistanceParams = {newDistanceToDisplay: string; oldDistanceToDisplay: string; newAmountToDisplay: string; oldAmountToDisplay: string};
type UpdatedTheDistanceMerchantParams = {translatedChangedField: string; newMerchant: string; oldMerchant: string; newAmountToDisplay: string; oldAmountToDisplay: string};

type FormattedMaxLengthParams = {formattedMaxLength: string};

Expand Down Expand Up @@ -437,7 +437,7 @@ export type {
ResolutionConstraintsParams,
RoomNameReservedErrorParams,
RoomRenamedToParams,
SetTheDistanceParams,
SetTheDistanceMerchantParams,
SetTheRequestParams,
SettleExpensifyCardParams,
SettledAfterAddedBankAccountParams,
Expand All @@ -454,7 +454,7 @@ export type {
TranslationFlatObject,
TranslationPaths,
UntilTimeParams,
UpdatedTheDistanceParams,
UpdatedTheDistanceMerchantParams,
UpdatedTheRequestParams,
UsePlusButtonParams,
UserIsAlreadyMemberParams,
Expand Down
32 changes: 26 additions & 6 deletions src/libs/ModifiedExpenseMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {PolicyTagLists, ReportAction} from '@src/types/onyx';
import * as CurrencyUtils from './CurrencyUtils';
import DateUtils from './DateUtils';
import * as Localize from './Localize';
import Log from './Log';
import * as PolicyUtils from './PolicyUtils';
import * as ReportActionsUtils from './ReportActionsUtils';
import * as ReportConnection from './ReportConnection';
Expand Down Expand Up @@ -94,13 +95,32 @@ function getMessageLine(prefix: string, messageFragments: string[]): string {
}, prefix);
}

function getForDistanceRequest(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string): string {
if (!oldDistance) {
return Localize.translateLocal('iou.setTheDistance', {newDistanceToDisplay: newDistance, newAmountToDisplay: newAmount});
function getForDistanceRequest(newMerchant: string, oldMerchant: string, newAmount: string, oldAmount: string): string {
let changedField: 'distance' | 'rate' = 'distance';

if (CONST.REGEX.DISTANCE_MERCHANT.test(newMerchant) && CONST.REGEX.DISTANCE_MERCHANT.test(oldMerchant)) {
const oldValues = oldMerchant.split('@');
const oldDistance = oldValues[0]?.trim() || '';
const oldRate = oldValues[1]?.trim() || '';
const newValues = newMerchant.split('@');
const newDistance = newValues[0]?.trim() || '';
const newRate = newValues[1]?.trim() || '';

if (oldDistance === newDistance && oldRate !== newRate) {
changedField = 'rate';
}
} else {
Log.hmmm("Distance request merchant doesn't match NewDot format. Defaulting to showing as distance changed.", {newMerchant, oldMerchant});
}

const translatedChangedField = Localize.translateLocal(`common.${changedField}`).toLowerCase();
if (!oldMerchant.length) {
return Localize.translateLocal('iou.setTheDistanceMerchant', {translatedChangedField, newMerchant, newAmountToDisplay: newAmount});
}
return Localize.translateLocal('iou.updatedTheDistance', {
newDistanceToDisplay: newDistance,
oldDistanceToDisplay: oldDistance,
return Localize.translateLocal('iou.updatedTheDistanceMerchant', {
translatedChangedField,
newMerchant,
oldMerchant,
newAmountToDisplay: newAmount,
oldAmountToDisplay: oldAmount,
});
Expand Down
8 changes: 5 additions & 3 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3431,6 +3431,7 @@ function getModifiedExpenseOriginalMessage(
transactionChanges: TransactionChanges,
isFromExpenseReport: boolean,
policy: OnyxInputOrEntry<Policy>,
updatedTransaction?: OnyxInputOrEntry<Transaction>,
): OriginalMessageModifiedExpense {
const originalMessage: OriginalMessageModifiedExpense = {};
// Remark: Comment field is the only one which has new/old prefixes for the keys (newComment/ oldComment),
Expand Down Expand Up @@ -3490,12 +3491,12 @@ function getModifiedExpenseOriginalMessage(
originalMessage.billable = transactionChanges?.billable ? Localize.translateLocal('common.billable').toLowerCase() : Localize.translateLocal('common.nonBillable').toLowerCase();
}

if ('customUnitRateID' in transactionChanges) {
if ('customUnitRateID' in transactionChanges && updatedTransaction?.comment?.customUnit?.customUnitRateID) {
originalMessage.oldAmount = TransactionUtils.getAmount(oldTransaction, isFromExpenseReport);
originalMessage.oldCurrency = TransactionUtils.getCurrency(oldTransaction);
originalMessage.oldMerchant = TransactionUtils.getMerchant(oldTransaction);

const modifiedDistanceFields = TransactionUtils.calculateAmountForUpdatedWaypointOrRate(oldTransaction, transactionChanges, policy, isFromExpenseReport);
const modifiedDistanceFields = TransactionUtils.calculateAmountForUpdatedWaypointOrRate(updatedTransaction, transactionChanges, policy, isFromExpenseReport);

// For the originalMessage, we should use the non-negative amount, similar to what TransactionUtils.getAmount does for oldAmount
originalMessage.amount = Math.abs(modifiedDistanceFields.modifiedAmount);
Expand Down Expand Up @@ -4867,8 +4868,9 @@ function buildOptimisticModifiedExpenseReportAction(
transactionChanges: TransactionChanges,
isFromExpenseReport: boolean,
policy: OnyxInputOrEntry<Policy>,
updatedTransaction?: OnyxInputOrEntry<Transaction>,
): OptimisticModifiedExpenseReportAction {
const originalMessage = getModifiedExpenseOriginalMessage(oldTransaction, transactionChanges, isFromExpenseReport, policy);
const originalMessage = getModifiedExpenseOriginalMessage(oldTransaction, transactionChanges, isFromExpenseReport, policy, updatedTransaction);
return {
actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE,
actorAccountID: currentUserAccountID,
Expand Down
11 changes: 9 additions & 2 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,14 @@ function getUpdatedTransaction(transaction: Transaction, transactionChanges: Tra
}

if (Object.hasOwn(transactionChanges, 'customUnitRateID')) {
updatedTransaction.modifiedCustomUnitRateID = transactionChanges.customUnitRateID;
updatedTransaction.comment = {
...(updatedTransaction?.comment ?? {}),
customUnit: {
...updatedTransaction?.comment?.customUnit,
customUnitRateID: transactionChanges.customUnitRateID,
defaultP2PRate: null,
},
};
shouldStopSmartscan = true;
}

Expand Down Expand Up @@ -830,7 +837,7 @@ function isPayAtEndExpense(transaction: Transaction | undefined | null): boolean
* Get custom unit rate (distance rate) ID from the transaction object
*/
function getRateID(transaction: OnyxInputOrEntry<Transaction>): string | undefined {
return transaction?.modifiedCustomUnitRateID ?? transaction?.comment?.customUnit?.customUnitRateID?.toString();
return transaction?.comment?.customUnit?.customUnitRateID ?? CONST.CUSTOM_UNITS.FAKE_P2P_ID;
}

/**
Expand Down
Loading
Loading