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

Create splitBill in the client #11597

Merged
merged 107 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
71a989b
create splitBill
luacmartins Oct 4, 2022
96e0e4e
rename API commands
luacmartins Oct 5, 2022
e662ea6
steps
luacmartins Oct 5, 2022
20ea8d5
create group chat and reportaction
luacmartins Oct 5, 2022
32c67a5
connect iouReports
luacmartins Oct 5, 2022
fbab3ed
add optimistic ioureports and reportactions
luacmartins Oct 5, 2022
4b3e33b
build optimisticData
luacmartins Oct 5, 2022
f74f967
call api
luacmartins Oct 5, 2022
833a17d
create buildSplitBillOnyxData
luacmartins Oct 5, 2022
db7654c
rm comments
luacmartins Oct 5, 2022
fb9234d
create const
luacmartins Oct 5, 2022
45190e4
use getChatByParticipants
luacmartins Oct 5, 2022
d30900f
add pendingActions
luacmartins Oct 5, 2022
bd85c31
add success and failure data
luacmartins Oct 5, 2022
f590dfa
add success and failure data
luacmartins Oct 6, 2022
13b86b8
add success and failure data for individual chats
luacmartins Oct 6, 2022
bc76ff8
add jsdocs to buildSplitBillOnyxData;
luacmartins Oct 6, 2022
26697f4
fix return order
luacmartins Oct 6, 2022
fca63c2
create createBillSplits
luacmartins Oct 6, 2022
b62cb93
revert changes
luacmartins Oct 6, 2022
17ad810
createSplitsAndBuildOnyxData
luacmartins Oct 6, 2022
27faca4
create IOU.calculateAmount
luacmartins Oct 6, 2022
edd0041
move calculateAmount to utils
luacmartins Oct 6, 2022
ee04fbd
add group data
luacmartins Oct 6, 2022
b5efc0d
add logic to call correct command
luacmartins Oct 7, 2022
b0b95cc
add created report action;
luacmartins Oct 7, 2022
c7b5656
rename method
luacmartins Oct 11, 2022
210adbb
rename chatReportID param
luacmartins Oct 11, 2022
1f8f521
stringify splits
luacmartins Oct 11, 2022
a14b172
update params
luacmartins Oct 11, 2022
69b30fb
rm console log
luacmartins Oct 11, 2022
f09272c
pass participants
luacmartins Oct 11, 2022
7f6730d
rm loggin
luacmartins Oct 11, 2022
9b724ab
fix errors with participants and created action
luacmartins Oct 11, 2022
bc410db
fix amount
luacmartins Oct 11, 2022
555aba8
fix group amount
luacmartins Oct 11, 2022
1b2919f
fix cached total
luacmartins Oct 11, 2022
dba44f5
pass existing ioureportid
luacmartins Oct 11, 2022
6e76758
rm useless conditional and update comments
luacmartins Oct 12, 2022
68d4d9d
enable confirm button when offline
luacmartins Oct 12, 2022
f58c0d0
add split type
luacmartins Oct 12, 2022
9587c54
create buildOptimisticIOUReportActionMessage
luacmartins Oct 12, 2022
12ff4a0
rm loading states
luacmartins Oct 12, 2022
1179bdf
fix iou badge prop types
luacmartins Oct 12, 2022
b6c57a3
add pending action to iouaction
luacmartins Oct 12, 2022
f0e811b
add pending action to ioupreview
luacmartins Oct 12, 2022
9a182d9
create getIOUReportActionMessage
luacmartins Oct 12, 2022
a5d771e
add translations to message
luacmartins Oct 12, 2022
9bfba9d
add formatted amount
luacmartins Oct 12, 2022
47e3fed
add comment
luacmartins Oct 12, 2022
da9a895
send amount in cents to api
luacmartins Oct 12, 2022
74dac7e
dismiss modal on split bill
luacmartins Oct 13, 2022
56d6a37
resolve conflicts
luacmartins Oct 13, 2022
eaef497
use getChatByParticipants
luacmartins Oct 13, 2022
5a19404
fix iouReport key
luacmartins Oct 13, 2022
54b09d6
fix participants login list
luacmartins Oct 13, 2022
c77fab4
remove getSplits
luacmartins Oct 13, 2022
a9daac9
pass clientID
luacmartins Oct 17, 2022
b28f87f
fix clientid
luacmartins Oct 17, 2022
8f4d882
use correct clientID
luacmartins Oct 17, 2022
d23d845
convert clientID to string
luacmartins Oct 18, 2022
bf26ba6
rm comment
luacmartins Oct 18, 2022
fe49af4
update sequence number
luacmartins Oct 18, 2022
0290695
update ioureport in chatreport key
luacmartins Oct 18, 2022
24ca139
compare numbers
luacmartins Oct 18, 2022
bcc173e
fix iou transactions
luacmartins Oct 18, 2022
4385830
use lowercase usernames
luacmartins Oct 19, 2022
9568845
use correct type, use waitForCollectionCallback
luacmartins Oct 19, 2022
966677f
rm translation
luacmartins Oct 19, 2022
c4674d2
add lastVisitedTimestamp and cleanup
luacmartins Oct 20, 2022
afc9d1e
Merge branch 'main' into cmartins-createSplitBill
luacmartins Oct 20, 2022
9ce4e28
add comment
luacmartins Oct 20, 2022
a4d7df6
create updateIOUOwnerAndTotal
luacmartins Oct 21, 2022
8f84ef5
fix style
luacmartins Oct 21, 2022
1a0da79
add comment to calculateTotal
luacmartins Oct 24, 2022
e50c6a2
update jsdocs and comments
luacmartins Oct 24, 2022
893e40e
add error handling
luacmartins Oct 24, 2022
904eccf
rm error copy
luacmartins Oct 24, 2022
89aa471
rm dateutils import
luacmartins Oct 24, 2022
9917c06
add comment
luacmartins Oct 25, 2022
ea57e1b
Merge branch 'main' into cmartins-createSplitBill
luacmartins Oct 25, 2022
d28dc18
fix failure data
luacmartins Oct 25, 2022
ef33a9d
fix failure data
luacmartins Oct 25, 2022
c7f7623
fix participant name
luacmartins Oct 25, 2022
07a35c3
fix prop type;
luacmartins Oct 25, 2022
421edab
fix console error
luacmartins Oct 25, 2022
7638af1
fix console error
luacmartins Oct 25, 2022
406de2e
update lastMessage in LHN
luacmartins Oct 26, 2022
fb30878
clean up last message
luacmartins Oct 26, 2022
2362e4e
update logic to select appropriate API command
luacmartins Oct 26, 2022
995c84e
resolve conflicts
luacmartins Oct 26, 2022
a4c6096
rm comment space
luacmartins Oct 27, 2022
5778731
use set if we are creating a report
luacmartins Oct 27, 2022
2e8e20f
use set for ioureport
luacmartins Oct 27, 2022
28b5b8a
allow split with 2 participants
luacmartins Oct 27, 2022
0e37011
fix participant selection
luacmartins Oct 27, 2022
8507241
add logic for single participant
luacmartins Oct 27, 2022
c0b50f1
add comment
luacmartins Oct 27, 2022
0526e8c
rm duplicate update
luacmartins Oct 27, 2022
d5a75d2
update set logic for iouReport
luacmartins Oct 27, 2022
842da25
Merge branch 'main' into cmartins-createSplitBill
luacmartins Oct 27, 2022
c67c37e
add comment
luacmartins Oct 27, 2022
628f7eb
resolve conflicts
luacmartins Oct 27, 2022
b2f5442
fix loading spinner
luacmartins Oct 28, 2022
2726466
early return for iouReport
luacmartins Oct 28, 2022
2fb6d24
Merge branch 'main' into cmartins-createSplitBill
luacmartins Oct 31, 2022
d20ea60
fix selectedParticipants;
luacmartins Oct 31, 2022
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.js
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,7 @@ const CONST = {
REPORT_ACTION_TYPE: {
PAY: 'pay',
CREATE: 'create',
SPLIT: 'split',
},
AMOUNT_MAX_LENGTH: 10,
},
Expand Down
68 changes: 7 additions & 61 deletions src/components/IOUConfirmationList.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Log from '../libs/Log';
import SettlementButton from './SettlementButton';
import ROUTES from '../ROUTES';
import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from './withCurrentUserPersonalDetails';
import * as IOUUtils from '../libs/IOUUtils';

const propTypes = {
/** Callback to inform parent modal of success */
Expand Down Expand Up @@ -143,7 +144,7 @@ class IOUConfirmationList extends Component {
getParticipantsWithAmount(participants) {
return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(
participants,
this.props.numberFormat(this.calculateAmount(participants) / 100, {
this.props.numberFormat(IOUUtils.calculateAmount(participants, this.props.iouAmount) / 100, {
style: 'currency',
currency: this.props.iou.selectedCurrencyCode,
}),
Expand Down Expand Up @@ -177,7 +178,7 @@ class IOUConfirmationList extends Component {

const formattedMyPersonalDetails = OptionsListUtils.getIOUConfirmationOptionsFromMyPersonalDetail(
this.props.currentUserPersonalDetails,
this.props.numberFormat(this.calculateAmount(selectedParticipants, true) / 100, {
this.props.numberFormat(IOUUtils.calculateAmount(selectedParticipants, this.props.iouAmount, true) / 100, {
style: 'currency',
currency: this.props.iou.selectedCurrencyCode,
}),
Expand Down Expand Up @@ -212,35 +213,6 @@ class IOUConfirmationList extends Component {
return sections;
}

/**
* Gets splits for the transaction
* @returns {Array|null}
*/
getSplits() {
// There can only be splits when there are multiple participants, so return early when there are not
// multiple participants
if (!this.props.hasMultipleParticipants) {
return null;
}
const selectedParticipants = this.getSelectedParticipants();
const splits = _.map(selectedParticipants, participant => ({
email: OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login),

// We should send in cents to API
// Cents is temporary and there must be support for other currencies in the future
amount: this.calculateAmount(selectedParticipants),
}));

splits.push({
email: OptionsListUtils.addSMSDomainIfPhoneNumber(this.props.currentUserPersonalDetails.login),

// The user is default and we should send in cents to API
// USD is temporary and there must be support for other currencies in the future
amount: this.calculateAmount(selectedParticipants, true),
});
return splits;
}

/**
* Returns selected options -- there is checkmark for every row in List for split flow
* @returns {Array}
Expand All @@ -256,30 +228,6 @@ class IOUConfirmationList extends Component {
];
}

/**
* Calculates the amount per user given a list of participants
* @param {Array} participants
* @param {Boolean} isDefaultUser
* @returns {Number}
*/
calculateAmount(participants, isDefaultUser = false) {
// Convert to cents before working with iouAmount to avoid
// javascript subtraction with decimal problem -- when dealing with decimals,
// because they are encoded as IEEE 754 floating point numbers, some of the decimal
// numbers cannot be represented with perfect accuracy.
// Cents is temporary and there must be support for other currencies in the future
const iouAmount = Math.round(parseFloat(this.props.iouAmount * 100));
const totalParticipants = participants.length + 1;
const amountPerPerson = Math.round(iouAmount / totalParticipants);

if (!isDefaultUser) { return amountPerPerson; }

const sumAmount = amountPerPerson * totalParticipants;
const difference = iouAmount - sumAmount;

return iouAmount !== sumAmount ? (amountPerPerson + difference) : amountPerPerson;
}

/**
* Toggle selected option's selected prop.
* @param {Object} option
Expand Down Expand Up @@ -318,7 +266,7 @@ class IOUConfirmationList extends Component {
Log.info(`[IOU] Sending money via: ${paymentMethod}`);
this.props.onSendMoney(paymentMethod);
} else {
this.props.onConfirm(this.getSplits());
this.props.onConfirm(selectedParticipants);
}
}

Expand All @@ -327,8 +275,8 @@ class IOUConfirmationList extends Component {
const shouldShowSettlementButton = this.props.iouType === CONST.IOU.IOU_TYPE.SEND;
const shouldDisableButton = selectedParticipants.length === 0;
const recipient = this.state.participants[0];
const canModifyParticipants = this.props.isIOUAttachedToExistingChatReport && this.props.hasMultipleParticipants;
const isLoading = this.props.iou.loading;
const canModifyParticipants = !this.props.isIOUAttachedToExistingChatReport && this.props.hasMultipleParticipants;

return (
<OptionsSelector
sections={this.getSections()}
Expand All @@ -339,7 +287,7 @@ class IOUConfirmationList extends Component {
textInputLabel={this.props.translate('iOUConfirmationList.whatsItFor')}
placeholderText={this.props.translate('common.optional')}
selectedOptions={this.getSelectedOptions()}
canSelectMultipleOptions={this.props.hasMultipleParticipants}
canSelectMultipleOptions={canModifyParticipants}
disableArrowKeysActions={!canModifyParticipants}
isDisabled={!canModifyParticipants}
hideAdditionalOptionStates
Expand All @@ -358,14 +306,12 @@ class IOUConfirmationList extends Component {
addBankAccountRoute={ROUTES.IOU_SEND_ADD_BANK_ACCOUNT}
addDebitCardRoute={ROUTES.IOU_SEND_ADD_DEBIT_CARD}
currency={this.props.iou.selectedCurrencyCode}
isLoading={isLoading}
/>
) : (
<ButtonWithMenu
isDisabled={shouldDisableButton}
onPress={(_event, value) => this.confirm(value)}
options={this.splitOrRequestOptions}
isLoading={isLoading}
/>
)}
/>
Expand Down
62 changes: 46 additions & 16 deletions src/libs/ReportUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -677,23 +677,58 @@ function buildOptimisticIOUReport(ownerEmail, userEmail, total, chatReportID, cu
};
}

/**
* @param {String} type - IOUReportAction type. Can be oneOf(create, decline, cancel, pay, split)
* @param {Number} total - IOU total in cents
* @param {Array} participants - List of logins for the IOU participants, excluding the current user login
* @param {String} comment - IOU comment
* @param {String} currency - IOU currency
* @returns {Array}
*/
function getIOUReportActionMessage(type, total, participants, comment, currency) {
luacmartins marked this conversation as resolved.
Show resolved Hide resolved
const amount = NumberFormatUtils.format(preferredLocale, total / 100, {style: 'currency', currency});
const isMultipleParticipantReport = participants.length > 1;
const displayNames = _.map(participants, participant => getDisplayNameForParticipant(allPersonalDetails[participant.login], isMultipleParticipantReport) || participant.login);
const from = displayNames.length < 3
? displayNames.join(' and ')
: `${displayNames.slice(0, -1).join(', ')}, and ${_.last(displayNames)}`;

let iouMessage;
switch (type) {
case CONST.IOU.REPORT_ACTION_TYPE.CREATE:
iouMessage = `Requested ${amount} from ${from}${comment && ` for ${comment}`}`;
break;
case CONST.IOU.REPORT_ACTION_TYPE.SPLIT:
iouMessage = `Split ${amount} with ${from}${comment && ` for ${comment}`}`;
break;
default:
break;
}

return [{
html: iouMessage,
text: iouMessage,
isEdited: false,
type: CONST.REPORT.MESSAGE.TYPE.COMMENT,
}];
}

/**
* Builds an optimistic IOU reportAction object
*
* @param {Number} sequenceNumber - Caller is responsible for providing a best guess at what the next sequenceNumber will be.
* @param {String} type - IOUReportAction type. Can be oneOf(create, decline, cancel, pay).
* @param {String} type - IOUReportAction type. Can be oneOf(create, decline, cancel, pay, split).
* @param {Number} amount - IOU amount in cents.
* @param {String} currency - IOU currency.
* @param {String} comment - User comment for the IOU.
* @param {Array} participants - An array with participants details.
* @param {String} paymentType - Only required if the IOUReportAction type is 'pay'. Can be oneOf(elsewhere, payPal, Expensify).
* @param {String} iouTransactionID - Only required if the IOUReportAction type is oneOf(cancel, decline). Generates a randomID as default.
* @param {String} iouReportID - Only required if the IOUReportActions type is oneOf(decline, cancel, pay). Generates a randomID as default.
* @param {String} debtorEmail - Email of the user that has to pay
* @param {String} locale - Locale of the user
*
* @returns {Object}
*/
function buildOptimisticIOUReportAction(sequenceNumber, type, amount, currency, comment, paymentType = '', iouTransactionID = '', iouReportID = '', debtorEmail = '', locale = 'en') {
function buildOptimisticIOUReportAction(sequenceNumber, type, amount, currency, comment, participants, paymentType = '', iouTransactionID = '', iouReportID = '') {
const IOUTransactionID = iouTransactionID || NumberUtils.rand64();
const IOUReportID = iouReportID || generateReportID();
const originalMessage = {
Expand All @@ -704,17 +739,6 @@ function buildOptimisticIOUReportAction(sequenceNumber, type, amount, currency,
IOUReportID,
type,
};
const formattedTotal = NumberFormatUtils.format(locale,
amount / 100, {
style: 'currency',
currency,
});
const message = [{
type: CONST.REPORT.MESSAGE.TYPE.COMMENT,
isEdited: false,
html: comment ? `Requested ${formattedTotal} from ${debtorEmail} for ${comment}` : `Requested ${formattedTotal} from ${debtorEmail}`,
text: comment ? `Requested ${formattedTotal} from ${debtorEmail} for ${comment}` : `Requested ${formattedTotal} from ${debtorEmail}`,
}];

// We store amount, comment, currency in IOUDetails when type = pay
if (type === CONST.IOU.REPORT_ACTION_TYPE.PAY) {
Expand All @@ -725,6 +749,11 @@ function buildOptimisticIOUReportAction(sequenceNumber, type, amount, currency,
originalMessage.paymentType = paymentType;
}

// IOUs of type split only exist in group DMs and those don't have an iouReport so we need to delete the IOUReportID key
if (type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT) {
delete originalMessage.IOUReportID;
}

return {
actionName: CONST.REPORT.ACTIONS.TYPE.IOU,
actorAccountID: currentUserAccountID,
Expand All @@ -733,8 +762,8 @@ function buildOptimisticIOUReportAction(sequenceNumber, type, amount, currency,
avatar: lodashGet(currentUserPersonalDetails, 'avatar', getDefaultAvatar(currentUserEmail)),
clientID: NumberUtils.generateReportActionClientID(),
isAttachment: false,
message,
originalMessage,
message: getIOUReportActionMessage(type, amount, participants, comment, currency),
person: [{
style: 'strong',
text: lodashGet(currentUserPersonalDetails, 'displayName', currentUserEmail),
Expand Down Expand Up @@ -1067,4 +1096,5 @@ export {
buildOptimisticReportAction,
shouldReportBeInOptionList,
getChatByParticipants,
getIOUReportActionMessage,
};
Loading