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

Implement report approvals #24639

Merged
merged 53 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
e1c0319
Add approveMoneyRequest action
youssef-lr Aug 7, 2023
b1e77ab
Add logic for showing the approve/settlement button
youssef-lr Aug 7, 2023
386d9f9
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 10, 2023
fa1bb92
Add helper methods
youssef-lr Aug 12, 2023
691ceba
Allow APPROVED action to be displayed
youssef-lr Aug 12, 2023
e0da0f3
Fix optimistic data for approved action
youssef-lr Aug 12, 2023
f7b422e
Add missing imports and code tidying up
youssef-lr Aug 12, 2023
9a8bef8
Display APPROVED action text in subtle color
youssef-lr Aug 12, 2023
2d50862
Display approved reports as approved and not paid
youssef-lr Aug 13, 2023
e8543c8
Fix lastMessageText showing duplicate actor name
youssef-lr Aug 16, 2023
00fb139
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 16, 2023
1140036
Code improvement
youssef-lr Aug 16, 2023
266cd4c
Create new IOU report if the current report is approved
youssef-lr Aug 16, 2023
5de9792
Display translated IOU/Report previews
youssef-lr Aug 16, 2023
75e9ed4
Fix bug showing approve button when report is settled
youssef-lr Aug 16, 2023
508021d
Display green dot properly
youssef-lr Aug 16, 2023
ecd428a
Cleanup
youssef-lr Aug 16, 2023
18c5198
Clean up
youssef-lr Aug 17, 2023
4e2a5c1
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 17, 2023
da32226
Use getIOUReportActionMessage to format APPROVED action message
youssef-lr Aug 18, 2023
d75e3f8
Add spanish translations
youssef-lr Aug 18, 2023
3930802
Code tidying up
youssef-lr Aug 18, 2023
c7d51cf
Fix IOU report being created instead of Expense report
youssef-lr Aug 18, 2023
d160aed
Code tidying up
youssef-lr Aug 18, 2023
07682c5
Fix bug
youssef-lr Aug 18, 2023
74b8caf
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 18, 2023
3b570e2
Bug fix
youssef-lr Aug 18, 2023
273966c
Fix code action
youssef-lr Aug 19, 2023
100f03d
Fix code actions
youssef-lr Aug 19, 2023
03cc982
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 19, 2023
909cd45
Linting
youssef-lr Aug 19, 2023
3462084
Style and translation
youssef-lr Aug 20, 2023
fca135f
Add back code removed by mistake
youssef-lr Aug 20, 2023
f7382f3
Fix test
youssef-lr Aug 20, 2023
2d3bf23
Style fix
youssef-lr Aug 21, 2023
c134640
Remove no longer needed helper func
youssef-lr Aug 22, 2023
216618b
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 22, 2023
21d5783
Show Pay button in report preview for admins when report is approved
youssef-lr Aug 22, 2023
10a287a
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 23, 2023
03e9513
Clean up
youssef-lr Aug 23, 2023
ceff45b
Apply suggestions from code review
youssef-lr Aug 23, 2023
2e373a8
Address PR comments
youssef-lr Aug 23, 2023
95dc9e2
Address comments
youssef-lr Aug 24, 2023
15ab698
Only display "Pay" button for the admin in the report preview
youssef-lr Aug 24, 2023
e7c4804
Optimise how policy is passed to money request componenets
youssef-lr Aug 24, 2023
c89f0a6
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 25, 2023
66b6724
Bug fix
youssef-lr Aug 26, 2023
4833ce4
Another bug fix
youssef-lr Aug 26, 2023
7dc3738
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 28, 2023
1b176a9
Merge branch 'main' into youssef_approve_money_request
youssef-lr Aug 28, 2023
575524c
Apply suggestions from code review
youssef-lr Aug 28, 2023
b341aa1
Address PR comments
youssef-lr Aug 28, 2023
577d9ad
Fix lint and approve button style
youssef-lr Aug 28, 2023
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
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ const CONST = {
ACTIONS: {
LIMIT: 50,
TYPE: {
APPROVED: 'APPROVED',
ADDCOMMENT: 'ADDCOMMENT',
CLOSED: 'CLOSED',
CREATED: 'CREATED',
Expand Down
8 changes: 4 additions & 4 deletions src/components/AvatarWithDisplayName.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const propTypes = {
/** The report currently being looked at */
report: reportPropTypes,

/** The policies which the user has access to and which the report could be tied to */
policies: PropTypes.shape({
/** The policy which the user has access to and which the report is tied to */
policy: PropTypes.shape({
/** Name of the policy */
name: PropTypes.string,
}),
Expand All @@ -47,7 +47,7 @@ const propTypes = {

const defaultProps = {
personalDetails: {},
policies: {},
policy: {},
report: {},
isAnonymous: false,
size: CONST.AVATAR_SIZE.DEFAULT,
Expand All @@ -72,7 +72,7 @@ function AvatarWithDisplayName(props) {
const subtitle = ReportUtils.getChatRoomSubtitle(props.report);
const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(props.report);
const isMoneyRequestOrReport = ReportUtils.isMoneyRequestReport(props.report) || ReportUtils.isMoneyRequest(props.report);
const icons = ReportUtils.getIcons(props.report, props.personalDetails, props.policies, true);
const icons = ReportUtils.getIcons(props.report, props.personalDetails, props.policy, true);
const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs([props.report.ownerAccountID], props.personalDetails);
const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(_.values(ownerPersonalDetails), false);
const shouldShowSubscriptAvatar = ReportUtils.shouldReportShowSubscript(props.report);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ const propTypes = {
/** Report, if we're showing the details for one and using AvatarWithDisplay */
report: iouReportPropTypes,

/** Policies, if we're showing the details for a report and need info about it for AvatarWithDisplay */
policies: PropTypes.shape({
/** The report's poolicy, if we're showing the details for a report and need info about it for AvatarWithDisplay */
youssef-lr marked this conversation as resolved.
Show resolved Hide resolved
policy: PropTypes.shape({
/** Name of the policy */
name: PropTypes.string,
}),
Expand Down
4 changes: 2 additions & 2 deletions src/components/HeaderWithBackButton/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function HeaderWithBackButton({
onDownloadButtonPress = () => {},
onThreeDotsButtonPress = () => {},
report = null,
policies = {},
policy = {},
personalDetails = {},
shouldShowAvatarWithDisplay = false,
shouldShowBackButton = true,
Expand Down Expand Up @@ -77,7 +77,7 @@ function HeaderWithBackButton({
{shouldShowAvatarWithDisplay && (
<AvatarWithDisplayName
report={report}
policies={policies}
policy={policy}
personalDetails={personalDetails}
/>
)}
Expand Down
102 changes: 69 additions & 33 deletions src/components/MoneyReportHeader.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import React, {useMemo} from 'react';
import {withOnyx} from 'react-native-onyx';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
import useLocalize from '../hooks/useLocalize';
import HeaderWithBackButton from './HeaderWithBackButton';
import iouReportPropTypes from '../pages/iouReportPropTypes';
import * as ReportUtils from '../libs/ReportUtils';
Expand All @@ -12,9 +13,10 @@ import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimen
import compose from '../libs/compose';
import Navigation from '../libs/Navigation/Navigation';
import ROUTES from '../ROUTES';
import SettlementButton from './SettlementButton';
import * as Policy from '../libs/actions/Policy';
import ONYXKEYS from '../ONYXKEYS';
import CONST from '../CONST';
import SettlementButton from './SettlementButton';
import Button from './Button';
import * as IOU from '../libs/actions/IOU';
import * as CurrencyUtils from '../libs/CurrencyUtils';
import reportPropTypes from '../pages/reportPropTypes';
Expand All @@ -23,10 +25,16 @@ const propTypes = {
/** The report currently being looked at */
report: iouReportPropTypes.isRequired,

/** The policies which the user has access to and which the report could be tied to */
policies: PropTypes.shape({
/** The policy tied to the money request report */
policy: PropTypes.shape({
/** Name of the policy */
name: PropTypes.string,

/** Type of the policy */
type: PropTypes.string,

/** The role of the current user in the policy */
role: PropTypes.string,
}).isRequired,

/** The chat report this report is linked to */
Expand All @@ -51,39 +59,47 @@ const defaultProps = {
},
};

function MoneyReportHeader(props) {
const moneyRequestReport = props.report;
function MoneyReportHeader({session, personalDetails, policy, chatReport, report: moneyRequestReport, isSmallScreenWidth}) {
const {translate} = useLocalize();
const isApproved = ReportUtils.isReportApproved(moneyRequestReport);
const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID);
const policy = props.policies[`${ONYXKEYS.COLLECTION.POLICY}${props.report.policyID}`];
const isPayer =
Policy.isAdminOfFreePolicy([policy]) || (ReportUtils.isMoneyRequestReport(moneyRequestReport) && lodashGet(props.session, 'accountID', null) === moneyRequestReport.managerID);
const reportTotal = ReportUtils.getMoneyRequestTotal(props.report);
const shouldShowSettlementButton = !isSettled && isPayer && !moneyRequestReport.isWaitingOnBankAccount && reportTotal !== 0;
const bankAccountRoute = ReportUtils.getBankAccountRoute(props.chatReport);
const shouldShowPaypal = Boolean(lodashGet(props.personalDetails, [moneyRequestReport.managerID, 'payPalMeAddress']));
const formattedAmount = CurrencyUtils.convertToDisplayString(reportTotal, props.report.currency);
const policyType = lodashGet(policy, 'type');
const isPolicyAdmin = policyType !== CONST.POLICY.TYPE.PERSONAL && lodashGet(policy, 'role') === CONST.POLICY.ROLE.ADMIN;
const isManager = ReportUtils.isMoneyRequestReport(moneyRequestReport) && lodashGet(session, 'accountID', null) === moneyRequestReport.managerID;
const isPayer = policyType === CONST.POLICY.TYPE.CORPORATE ? isPolicyAdmin && isApproved : isPolicyAdmin || (ReportUtils.isMoneyRequestReport(moneyRequestReport) && isManager);
const shouldShowSettlementButton = useMemo(() => isPayer && !isSettled, [isPayer, isSettled]);
youssef-lr marked this conversation as resolved.
Show resolved Hide resolved
const shouldShowApproveButton = useMemo(() => {
if (policyType === CONST.POLICY.TYPE.FREE) {
return false;
}
return isManager && !isApproved && !isSettled;
}, [policyType, isManager, isApproved, isSettled]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the policyType is personal in case of IOU then we should also not show the Approved button but its not clear from this method that will be the case

const reportTotal = ReportUtils.getMoneyRequestTotal(moneyRequestReport);
const bankAccountRoute = ReportUtils.getBankAccountRoute(chatReport);
const shouldShowPaypal = Boolean(lodashGet(personalDetails, [moneyRequestReport.managerID, 'payPalMeAddress']));
const formattedAmount = CurrencyUtils.convertToDisplayString(reportTotal, moneyRequestReport.currency);

return (
<View style={[styles.pt0]}>
<HeaderWithBackButton
shouldShowAvatarWithDisplay
shouldShowPinButton={false}
report={props.report}
policies={props.policies}
personalDetails={props.personalDetails}
shouldShowBackButton={props.isSmallScreenWidth}
report={moneyRequestReport}
policy={policy}
personalDetails={personalDetails}
shouldShowBackButton={isSmallScreenWidth}
onBackButtonPress={() => Navigation.goBack(ROUTES.HOME, false, true)}
shouldShowBorderBottom={!shouldShowSettlementButton || !props.isSmallScreenWidth}
shouldShowBorderBottom={!shouldShowSettlementButton || !isSmallScreenWidth}
>
{shouldShowSettlementButton && !props.isSmallScreenWidth && (
{shouldShowSettlementButton && !isSmallScreenWidth && (
<View style={[styles.pv2]}>
<SettlementButton
currency={props.report.currency}
policyID={props.report.policyID}
currency={moneyRequestReport.currency}
policyID={moneyRequestReport.policyID}
shouldShowPaypal={shouldShowPaypal}
chatReportID={props.chatReport.reportID}
iouReport={props.report}
onPress={(paymentType) => IOU.payMoneyRequest(paymentType, props.chatReport, props.report)}
chatReportID={chatReport.reportID}
iouReport={moneyRequestReport}
onPress={(paymentType) => IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)}
enablePaymentsRoute={ROUTES.BANK_ACCOUNT_NEW}
addBankAccountRoute={bankAccountRoute}
shouldShowPaymentOptions
Expand All @@ -92,23 +108,43 @@ function MoneyReportHeader(props) {
/>
</View>
)}
{shouldShowApproveButton && !isSmallScreenWidth && (
<View style={[styles.pv2]}>
<Button
success
text={translate('iou.approve')}
style={[styles.mnw120]}
onPress={() => IOU.approveMoneyRequest(moneyRequestReport)}
/>
</View>
)}
</HeaderWithBackButton>
{shouldShowSettlementButton && props.isSmallScreenWidth && (
<View style={[styles.ph5, styles.pb2, props.isSmallScreenWidth && styles.borderBottom]}>
{shouldShowSettlementButton && isSmallScreenWidth && (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we ever show Settlement and Approve button at the same time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I think the conditionals implemented will prevent this, this specifically const isPayer = policyType === CONST.POLICY.TYPE.CORPORATE ? isPolicyAdmin && isApproved

<View style={[styles.ph5, styles.pb2, isSmallScreenWidth && styles.borderBottom]}>
<SettlementButton
currency={props.report.currency}
policyID={props.report.policyID}
currency={moneyRequestReport.currency}
policyID={moneyRequestReport.policyID}
shouldShowPaypal={shouldShowPaypal}
chatReportID={props.report.chatReportID}
iouReport={props.report}
onPress={(paymentType) => IOU.payMoneyRequest(paymentType, props.chatReport, props.report)}
chatReportID={moneyRequestReport.chatReportID}
iouReport={moneyRequestReport}
onPress={(paymentType) => IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)}
enablePaymentsRoute={ROUTES.BANK_ACCOUNT_NEW}
addBankAccountRoute={bankAccountRoute}
shouldShowPaymentOptions
formattedAmount={formattedAmount}
/>
</View>
)}
{shouldShowApproveButton && isSmallScreenWidth && (
<View style={[styles.pv2]}>
<Button
success
text={translate('iou.approve')}
style={[styles.w100]}
onPress={() => IOU.approveMoneyRequest(moneyRequestReport)}
/>
</View>
)}
</View>
);
}
Expand Down
9 changes: 5 additions & 4 deletions src/components/MoneyRequestHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const propTypes = {
/** The expense report or iou report (only will have a value if this is a transaction thread) */
parentReport: iouReportPropTypes,

/** The policies which the user has access to and which the report could be tied to */
policies: PropTypes.shape({
/** The policy which the report is tied to */
policy: PropTypes.shape({
/** Name of the policy */
name: PropTypes.string,
}).isRequired,
Expand Down Expand Up @@ -58,6 +58,7 @@ function MoneyRequestHeader(props) {
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
const moneyRequestReport = props.parentReport;
const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID);

const parentReportAction = ReportActionsUtils.getParentReportAction(props.report);

// Only the requestor can take delete the request, admins can only edit it.
Expand Down Expand Up @@ -90,7 +91,7 @@ function MoneyRequestHeader(props) {
]}
threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(props.windowWidth)}
report={report}
policies={props.policies}
policy={props.policy}
personalDetails={props.personalDetails}
shouldShowBackButton={props.isSmallScreenWidth}
onBackButtonPress={() => Navigation.goBack(ROUTES.HOME, false, true)}
Expand Down Expand Up @@ -122,7 +123,7 @@ export default compose(
key: ONYXKEYS.SESSION,
},
parentReport: {
key: (props) => `${ONYXKEYS.COLLECTION.REPORT}${props.report.parentReportID}`,
key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`,
},
}),
)(MoneyRequestHeader);
4 changes: 3 additions & 1 deletion src/components/ReportActionItem/MoneyRequestPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ function MoneyRequestPreview(props) {
}

let message = props.translate('iou.cash');
if (props.iouReport.isWaitingOnBankAccount) {
if (ReportUtils.isControlPolicyExpenseReport(props.iouReport) && ReportUtils.isReportApproved(props.iouReport) && !ReportUtils.isSettled(props.iouReport)) {
message += ` • ${props.translate('iou.approved')}`;
} else if (props.iouReport.isWaitingOnBankAccount) {
message += ` • ${props.translate('iou.pending')}`;
} else if (ReportUtils.isSettled(props.iouReport.reportID)) {
message += ` • ${props.translate('iou.settledExpensify')}`;
Expand Down
18 changes: 15 additions & 3 deletions src/components/ReportActionItem/ReportPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import styles from '../../styles/styles';
import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
import withLocalize, {withLocalizePropTypes} from '../withLocalize';
import compose from '../../libs/compose';
import CONST from '../../CONST';
import ONYXKEYS from '../../ONYXKEYS';
import ControlSelection from '../../libs/ControlSelection';
import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
Expand Down Expand Up @@ -41,6 +42,9 @@ const propTypes = {
// eslint-disable-next-line react/no-unused-prop-types
iouReportID: PropTypes.string.isRequired,

/** The report's policyID, used for Onyx subscription */
policyID: PropTypes.string.isRequired,

/* Onyx Props */
/** chatReport associated with iouReport */
chatReport: reportPropTypes,
Expand Down Expand Up @@ -140,15 +144,20 @@ function ReportPreview(props) {
};

const getPreviewMessage = () => {
const managerName = ReportUtils.isPolicyExpenseChat(props.chatReport) ? ReportUtils.getPolicyName(props.chatReport) : ReportUtils.getDisplayNameForParticipant(managerID, true);
if (isScanning) {
return props.translate('common.receipt');
}
if (ReportUtils.isControlPolicyExpenseChat(props.chatReport) && ReportUtils.isReportApproved(props.iouReport)) {
youssef-lr marked this conversation as resolved.
Show resolved Hide resolved
return props.translate('iou.managerApproved', {manager: ReportUtils.getDisplayNameForParticipant(managerID, true)});
}
const managerName = ReportUtils.isPolicyExpenseChat(props.chatReport) ? ReportUtils.getPolicyName(props.chatReport) : ReportUtils.getDisplayNameForParticipant(managerID, true);
return props.translate(iouSettled || props.iouReport.isWaitingOnBankAccount ? 'iou.payerPaid' : 'iou.payerOwes', {payer: managerName});
};

const bankAccountRoute = ReportUtils.getBankAccountRoute(props.chatReport);
const shouldShowSettlementButton = !_.isEmpty(props.iouReport) && isCurrentUserManager && !iouSettled && !props.iouReport.isWaitingOnBankAccount && reportTotal !== 0;
const shouldShowSettlementButton = ReportUtils.isControlPolicyExpenseChat(props.chatReport)
? props.policy.role === CONST.POLICY.ROLE.ADMIN && ReportUtils.isReportApproved(props.iouReport) && !iouSettled
: !_.isEmpty(props.iouReport) && isCurrentUserManager && !iouSettled && !props.iouReport.isWaitingOnBankAccount && reportTotal !== 0;

return (
<View style={[styles.chatItemMessage, ...props.containerStyles]}>
Expand Down Expand Up @@ -202,7 +211,7 @@ function ReportPreview(props) {
{shouldShowSettlementButton && (
<SettlementButton
currency={props.iouReport.currency}
policyID={props.iouReport.policyID}
policyID={props.policyID}
chatReportID={props.chatReportID}
iouReport={props.iouReport}
onPress={(paymentType) => IOU.payMoneyRequest(paymentType, props.chatReport, props.iouReport)}
Expand All @@ -225,6 +234,9 @@ ReportPreview.displayName = 'ReportPreview';
export default compose(
withLocalize,
withOnyx({
policy: {
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
},
chatReport: {
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`,
},
Expand Down
3 changes: 3 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ export default {
},
iou: {
amount: 'Amount',
approve: 'Approve',
approved: 'Approved',
cash: 'Cash',
split: 'Split',
request: 'Request',
Expand Down Expand Up @@ -426,6 +428,7 @@ export default {
payerOwes: ({payer}) => `${payer} owes: `,
payerPaidAmount: ({payer, amount}) => `${payer} paid ${amount}`,
payerPaid: ({payer}) => `${payer} paid: `,
managerApproved: ({manager}) => `${manager} approved:`,
payerSettled: ({amount}) => `paid ${amount}`,
waitingOnBankAccount: ({submitterDisplayName}) => `started settling up, payment is held until ${submitterDisplayName} adds a bank account`,
settledAfterAddedBankAccount: ({submitterDisplayName, amount}) => `${submitterDisplayName} added a bank account. The ${amount} payment has been made.`,
Expand Down
3 changes: 3 additions & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,8 @@ export default {
},
iou: {
amount: 'Importe',
approve: 'Aprobar',
approved: 'Aprobado',
cash: 'Efectivo',
split: 'Dividir',
request: 'Solicitar',
Expand Down Expand Up @@ -425,6 +427,7 @@ export default {
payerOwes: ({payer}) => `${payer} debe: `,
payerPaidAmount: ({payer, amount}) => `${payer} pagó ${amount}`,
payerPaid: ({payer}) => `${payer} pagó: `,
managerApproved: ({manager}) => `${manager} aprobó:`,
payerSettled: ({amount}) => `pagó ${amount}`,
waitingOnBankAccount: ({submitterDisplayName}) => `inicio el pago, pero no se procesará hasta que ${submitterDisplayName} añada una cuenta bancaria`,
settledAfterAddedBankAccount: ({submitterDisplayName, amount}) => `${submitterDisplayName} añadió una cuenta bancaria. El pago de ${amount} se ha realizado.`,
Expand Down
Loading