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

[Unapprove] Add unapprove feature to approved reports #44229

Merged
merged 48 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
227ce21
add manually reimbursed func
rushatgabhane Jun 24, 2024
076dba0
add canUnapproveRequest
rushatgabhane Jun 24, 2024
0a2f286
add menu item type
rushatgabhane Jun 24, 2024
43564f4
add unapprove lang
rushatgabhane Jun 24, 2024
f212e2d
show menu item for unapprove
rushatgabhane Jun 24, 2024
e8c0adb
add func to unapprove request
rushatgabhane Jun 24, 2024
c17d876
fix onyx type for unapprove
rushatgabhane Jun 24, 2024
1754187
rm unapprove as olddot action
rushatgabhane Jun 24, 2024
6274247
add backwards icon
rushatgabhane Jun 24, 2024
b588e81
use backwards icon
rushatgabhane Jun 24, 2024
a1cdab6
add optimistic unapproved action
rushatgabhane Jun 24, 2024
1531248
add unapprove api type
rushatgabhane Jun 24, 2024
3213e7e
add unapprove api command call
rushatgabhane Jun 24, 2024
1b55327
call api on unapprove click
rushatgabhane Jun 24, 2024
bdbe266
add warning if connected to accounting
rushatgabhane Jun 24, 2024
341244e
add warning if connected to accounting
rushatgabhane Jun 24, 2024
d4a052b
rm full
rushatgabhane Jun 24, 2024
35ef33d
add spanish
rushatgabhane Jun 24, 2024
36cc15f
rm optimisticChatReportData
rushatgabhane Jun 24, 2024
cc89578
add unapprove to muted actions
rushatgabhane Jun 24, 2024
72013c0
add bold style to prompt
rushatgabhane Jun 24, 2024
1478954
rename to circular arrow backwards
rushatgabhane Jun 26, 2024
5ce3551
rename to circular arrow backwards
rushatgabhane Jun 26, 2024
f27f0dc
rename to expense report
rushatgabhane Jun 26, 2024
97c3220
rm const
rushatgabhane Jun 26, 2024
05b5696
rm const
rushatgabhane Jun 26, 2024
ead7a1c
rm unused lang
rushatgabhane Jun 26, 2024
cd6e8f1
revert: rm unused lang
rushatgabhane Jun 26, 2024
1b6dc73
revert: rm unused lang
rushatgabhane Jun 26, 2024
68b5c68
merge mainn
rushatgabhane Jun 26, 2024
8ba06e0
add param type for unapprove
rushatgabhane Jun 26, 2024
cfa5803
call api with parms
rushatgabhane Jun 26, 2024
538e621
run prettier
rushatgabhane Jun 27, 2024
b87b726
add spanish translation
rushatgabhane Jun 27, 2024
a59c5b6
Merge branch 'main' of github.com:rushatgabhane/exfy into unapprove-b…
rushatgabhane Jun 27, 2024
4a3ebfa
fix type
rushatgabhane Jun 27, 2024
0280572
fix type
rushatgabhane Jun 27, 2024
737f730
chg order
rushatgabhane Jun 27, 2024
1b59e17
rename to expense report
rushatgabhane Jun 27, 2024
7441936
rename stuff
rushatgabhane Jun 27, 2024
35d10e0
move to func
rushatgabhane Jun 27, 2024
b6b49e7
move to func
rushatgabhane Jun 27, 2024
5e23460
show warning if connected to accounting
rushatgabhane Jul 6, 2024
4aa5d8e
get connected integration name
rushatgabhane Jul 6, 2024
afd5eac
default to none
rushatgabhane Jul 6, 2024
7c05a27
fix merge conflict
rushatgabhane Jul 6, 2024
a422850
fix lint
rushatgabhane Jul 6, 2024
c90b703
rm unnecessary setstate
rushatgabhane Jul 6, 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
9 changes: 9 additions & 0 deletions assets/images/circular-arrow-backwards.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ const CONST = {
TASK_EDITED: 'TASKEDITED',
TASK_REOPENED: 'TASKREOPENED',
TRIPPREVIEW: 'TRIPPREVIEW',
UNAPPROVED: 'UNAPPROVED', // OldDot Action
UNAPPROVED: 'UNAPPROVED',
UNHOLD: 'UNHOLD',
UNSHARE: 'UNSHARE', // OldDot Action
UPDATE_GROUP_CHAT_MEMBER_ROLE: 'UPDATEGROUPCHATMEMBERROLE',
Expand Down Expand Up @@ -2335,6 +2335,7 @@ const CONST = {
PRIVATE_NOTES: 'privateNotes',
DELETE: 'delete',
MARK_AS_INCOMPLETE: 'markAsIncomplete',
UNAPPROVE: 'unapprove',
},
EDIT_REQUEST_FIELD: {
AMOUNT: 'amount',
Expand Down
2 changes: 2 additions & 0 deletions src/components/Icon/Expensicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import ChatBubbles from '@assets/images/chatbubbles.svg';
import CheckCircle from '@assets/images/check-circle.svg';
import CheckmarkCircle from '@assets/images/checkmark-circle.svg';
import Checkmark from '@assets/images/checkmark.svg';
import CircularArrowBackwards from '@assets/images/circular-arrow-backwards.svg';
import Close from '@assets/images/close.svg';
import ClosedSign from '@assets/images/closed-sign.svg';
import Coins from '@assets/images/coins.svg';
Expand Down Expand Up @@ -201,6 +202,7 @@ export {
Wrench,
BackArrow,
Bank,
CircularArrowBackwards,
Bill,
Bell,
BellSlash,
Expand Down
20 changes: 20 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,11 @@ export default {
removed: 'removed',
transactionPending: 'Transaction pending.',
chooseARate: ({unit}: ReimbursementRateParams) => `Select a workspace reimbursement rate per ${unit}`,
unapprove: 'Unapprove',
unapproveReport: 'Unapprove report',
headsUp: 'Heads up!',
unapproveWithIntegrationWarning: (accountingIntegration: string) =>
`This report has already been exported to ${accountingIntegration}. Changes to this report in Expensify may lead to data discrepancies and Expensify Card reconciliation issues. Are you sure you want to unapprove this report?`,
},
notificationPreferencesPage: {
header: 'Notification preferences',
Expand Down Expand Up @@ -2759,6 +2764,21 @@ export default {
xero: 'Xero',
netsuite: 'NetSuite',
intacct: 'Sage Intacct',
connectionName: (integration: ConnectionName) => {
switch (integration) {
case CONST.POLICY.CONNECTIONS.NAME.QBO:
return 'Quickbooks Online';
case CONST.POLICY.CONNECTIONS.NAME.XERO:
return 'Xero';
case CONST.POLICY.CONNECTIONS.NAME.NETSUITE:
return 'NetSuite';
case CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT:
return 'Sage Intacct';
default: {
return '';
}
}
},
setup: 'Connect',
lastSync: (relativeDate: string) => `Last synced ${relativeDate}`,
import: 'Import',
Expand Down
20 changes: 20 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,11 @@ export default {
removed: 'eliminó',
transactionPending: 'Transacción pendiente.',
chooseARate: ({unit}: ReimbursementRateParams) => `Selecciona una tasa de reembolso por ${unit} del espacio de trabajo`,
unapprove: 'Desaprobar',
unapproveReport: 'Anular la aprobación del informe',
headsUp: 'Atención!',
unapproveWithIntegrationWarning: (accountingIntegration: string) =>
`Este informe ya se ha exportado a ${accountingIntegration}. Los cambios realizados en este informe en Expensify pueden provocar discrepancias en los datos y problemas de conciliación de la tarjeta Expensify. ¿Está seguro de que desea anular la aprobación de este informe?`,
},
notificationPreferencesPage: {
header: 'Preferencias de avisos',
Expand Down Expand Up @@ -2741,6 +2746,21 @@ export default {
xero: 'Xero',
netsuite: 'NetSuite',
intacct: 'Sage Intacct',
connectionName: (integration: ConnectionName) => {
switch (integration) {
case CONST.POLICY.CONNECTIONS.NAME.QBO:
return 'Quickbooks Online';
case CONST.POLICY.CONNECTIONS.NAME.XERO:
return 'Xero';
case CONST.POLICY.CONNECTIONS.NAME.NETSUITE:
return 'NetSuite';
case CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT:
return 'Sage Intacct';
default: {
return '';
}
}
},
setup: 'Configurar',
lastSync: (relativeDate: string) => `Recién sincronizado ${relativeDate}`,
import: 'Importar',
Expand Down
6 changes: 6 additions & 0 deletions src/libs/API/parameters/UnapproveExpenseReportParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type UnapproveExpenseReportParams = {
reportID: string;
reportActionID: string;
};

export default UnapproveExpenseReportParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ export type {default as CreateDistanceRequestParams} from './CreateDistanceReque
export type {default as StartSplitBillParams} from './StartSplitBillParams';
export type {default as SendMoneyParams} from './SendMoneyParams';
export type {default as ApproveMoneyRequestParams} from './ApproveMoneyRequestParams';
export type {default as UnapproveExpenseReportParams} from './UnapproveExpenseReportParams';
export type {default as EditMoneyRequestParams} from './EditMoneyRequestParams';
export type {default as ReplaceReceiptParams} from './ReplaceReceiptParams';
export type {default as SubmitReportParams} from './SubmitReportParams';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ const WRITE_COMMANDS = {
SEND_MONEY_ELSEWHERE: 'SendMoneyElsewhere',
SEND_MONEY_WITH_WALLET: 'SendMoneyWithWallet',
APPROVE_MONEY_REQUEST: 'ApproveMoneyRequest',
UNAPPROVE_EXPENSE_REPORT: 'UnapproveExpenseReport',
EDIT_MONEY_REQUEST: 'EditMoneyRequest',
REPLACE_RECEIPT: 'ReplaceReceipt',
SUBMIT_REPORT: 'SubmitReport',
Expand Down Expand Up @@ -430,6 +431,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.SEND_MONEY_ELSEWHERE]: Parameters.SendMoneyParams;
[WRITE_COMMANDS.SEND_MONEY_WITH_WALLET]: Parameters.SendMoneyParams;
[WRITE_COMMANDS.APPROVE_MONEY_REQUEST]: Parameters.ApproveMoneyRequestParams;
[WRITE_COMMANDS.UNAPPROVE_EXPENSE_REPORT]: Parameters.UnapproveExpenseReportParams;
[WRITE_COMMANDS.EDIT_MONEY_REQUEST]: Parameters.EditMoneyRequestParams;
[WRITE_COMMANDS.REPLACE_RECEIPT]: Parameters.ReplaceReceiptParams;
[WRITE_COMMANDS.SUBMIT_REPORT]: Parameters.SubmitReportParams;
Expand Down
1 change: 0 additions & 1 deletion src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,6 @@ function isOldDotReportAction(action: ReportAction | OldDotReportAction) {
CONST.REPORT.ACTIONS.TYPE.SHARE,
CONST.REPORT.ACTIONS.TYPE.STRIPE_PAID,
CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL,
CONST.REPORT.ACTIONS.TYPE.UNAPPROVED,
CONST.REPORT.ACTIONS.TYPE.UNSHARE,
CONST.REPORT.ACTIONS.TYPE.DELETED_ACCOUNT,
CONST.REPORT.ACTIONS.TYPE.DONATION,
Expand Down
47 changes: 47 additions & 0 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ type OptimisticApprovedReportAction = Pick<
'actionName' | 'actorAccountID' | 'automatic' | 'avatar' | 'isAttachment' | 'originalMessage' | 'message' | 'person' | 'reportActionID' | 'shouldShow' | 'created' | 'pendingAction'
>;

type OptimisticUnapprovedReportAction = Pick<
ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.UNAPPROVED>,
'actionName' | 'actorAccountID' | 'automatic' | 'avatar' | 'isAttachment' | 'originalMessage' | 'message' | 'person' | 'reportActionID' | 'shouldShow' | 'created' | 'pendingAction'
>;

type OptimisticSubmittedReportAction = Pick<
ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.SUBMITTED>,
| 'actionName'
Expand Down Expand Up @@ -778,6 +783,13 @@ function isReportApproved(reportOrID: OnyxInputOrEntry<Report> | string, parentR
return report?.stateNum === CONST.REPORT.STATE_NUM.APPROVED && report?.statusNum === CONST.REPORT.STATUS_NUM.APPROVED;
}

/**
* Checks if the supplied report has been manually reimbursed
*/
function isReportManuallyReimbursed(report: OnyxEntry<Report>): boolean {
return report?.stateNum === CONST.REPORT.STATE_NUM.APPROVED && report?.statusNum === CONST.REPORT.STATUS_NUM.REIMBURSED;
}

/**
* Checks if the supplied report is an expense report in Open state and status.
*/
Expand Down Expand Up @@ -4039,6 +4051,9 @@ function getIOUReportActionMessage(iouReportID: string, type: string, total: num
case CONST.REPORT.ACTIONS.TYPE.APPROVED:
iouMessage = `approved ${amount}`;
break;
case CONST.REPORT.ACTIONS.TYPE.UNAPPROVED:
iouMessage = `unapproved ${amount}`;
break;
case CONST.IOU.REPORT_ACTION_TYPE.CREATE:
iouMessage = `submitted ${amount}${comment && ` for ${comment}`}`;
break;
Expand Down Expand Up @@ -4201,6 +4216,36 @@ function buildOptimisticApprovedReportAction(amount: number, currency: string, e
};
}

/**
* Builds an optimistic APPROVED report action with a randomly generated reportActionID.
*/
function buildOptimisticUnapprovedReportAction(amount: number, currency: string, expenseReportID: string): OptimisticUnapprovedReportAction {
return {
actionName: CONST.REPORT.ACTIONS.TYPE.UNAPPROVED,
actorAccountID: currentUserAccountID,
automatic: false,
avatar: getCurrentUserAvatar(),
isAttachment: false,
originalMessage: {
amount,
currency,
expenseReportID,
},
message: getIOUReportActionMessage(expenseReportID, CONST.REPORT.ACTIONS.TYPE.UNAPPROVED, Math.abs(amount), '', currency),
person: [
{
style: 'strong',
text: getCurrentUserDisplayNameOrEmail(),
type: 'TEXT',
},
],
reportActionID: NumberUtils.rand64(),
shouldShow: true,
created: DateUtils.getDBTime(),
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
};
}

/**
* Builds an optimistic MOVED report action with a randomly generated reportActionID.
* This action is used when we move reports across workspaces.
Expand Down Expand Up @@ -7039,6 +7084,7 @@ export {
areAllRequestsBeingSmartScanned,
buildOptimisticAddCommentReportAction,
buildOptimisticApprovedReportAction,
buildOptimisticUnapprovedReportAction,
buildOptimisticCancelPaymentReportAction,
buildOptimisticChangedTaskAssigneeReportAction,
buildOptimisticChatReport,
Expand Down Expand Up @@ -7251,6 +7297,7 @@ export {
isPublicAnnounceRoom,
isPublicRoom,
isReportApproved,
isReportManuallyReimbursed,
isReportDataReady,
isReportFieldDisabled,
isReportFieldOfTypeTitle,
Expand Down
91 changes: 91 additions & 0 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {
StartSplitBillParams,
SubmitReportParams,
TrackExpenseParams,
UnapproveExpenseReportParams,
UpdateMoneyRequestParams,
} from '@libs/API/parameters';
import {WRITE_COMMANDS} from '@libs/API/types';
Expand Down Expand Up @@ -6359,6 +6360,95 @@ function approveMoneyRequest(expenseReport: OnyxEntry<OnyxTypes.Report>, full?:
API.write(WRITE_COMMANDS.APPROVE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData});
}

function unapproveExpenseReport(expenseReport: OnyxEntry<OnyxTypes.Report>) {
if (isEmptyObject(expenseReport)) {
return;
}

const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`] ?? null;

const optimisticUnapprovedReportAction = ReportUtils.buildOptimisticUnapprovedReportAction(expenseReport.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID);
const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, CONST.REPORT.STATUS_NUM.SUBMITTED);

const optimisticReportActionData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
value: {
[optimisticUnapprovedReportAction.reportActionID]: {
...(optimisticUnapprovedReportAction as OnyxTypes.ReportAction),
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
},
},
};
const optimisticIOUReportData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`,
value: {
...expenseReport,
lastMessageText: ReportActionsUtils.getReportActionText(optimisticUnapprovedReportAction),
lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticUnapprovedReportAction),
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
pendingFields: {
partial: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
},
};

const optimisticNextStepData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`,
value: optimisticNextStep,
};

const optimisticData: OnyxUpdate[] = [optimisticIOUReportData, optimisticReportActionData, optimisticNextStepData];

const successData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
value: {
[optimisticUnapprovedReportAction.reportActionID]: {
pendingAction: null,
},
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`,
value: {
pendingFields: {
partial: null,
},
},
},
];

const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
value: {
[optimisticUnapprovedReportAction.reportActionID]: {
errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'),
},
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`,
value: currentNextStep,
},
];

const parameters: UnapproveExpenseReportParams = {
reportID: expenseReport.reportID,
reportActionID: optimisticUnapprovedReportAction.reportActionID,
};

API.write(WRITE_COMMANDS.UNAPPROVE_EXPENSE_REPORT, parameters, {optimisticData, successData, failureData});
}

function submitReport(expenseReport: OnyxTypes.Report) {
if (expenseReport.policyID && SubscriptionUtils.shouldRestrictUserBillableActions(expenseReport.policyID)) {
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(expenseReport.policyID));
Expand Down Expand Up @@ -7016,6 +7106,7 @@ function getIOURequestPolicyID(transaction: OnyxEntry<OnyxTypes.Transaction>, re

export {
approveMoneyRequest,
unapproveExpenseReport,
canApproveIOU,
canIOUBePaid,
cancelPayment,
Expand Down
Loading
Loading