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
66 changes: 29 additions & 37 deletions src/libs/IOUUtils.js → src/libs/IOUUtils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import _ from 'underscore';
import CONST from '../CONST';
import * as TransactionUtils from './TransactionUtils';
import * as CurrencyUtils from './CurrencyUtils';
import {Report, Transaction} from '../types/onyx';

/**
* Calculates the amount per user given a list of participants
*
* @param {Number} numberOfParticipants - Number of participants in the chat. It should not include the current user.
* @param {Number} total - IOU total amount in backend format (cents, no matter the currency)
* @param {String} currency - This is used to know how many decimal places are valid to use when splitting the total
* @param {Boolean} isDefaultUser - Whether we are calculating the amount for the current user
* @returns {Number}
* @param numberOfParticipants - Number of participants in the chat. It should not include the current user.
* @param total - IOU total amount in backend format (cents, no matter the currency)
* @param currency - This is used to know how many decimal places are valid to use when splitting the total
* @param isDefaultUser - Whether we are calculating the amount for the current user
*/
function calculateAmount(numberOfParticipants, total, currency, isDefaultUser = false) {
function calculateAmount(numberOfParticipants: number, total: number, currency: string, isDefaultUser = false): number {
// Since the backend can maximum store 2 decimal places, any currency with more than 2 decimals
// has to be capped to 2 decimal places
const currencyUnit = Math.min(100, CurrencyUtils.getCurrencyUnit(currency));
Expand All @@ -34,59 +33,52 @@ function calculateAmount(numberOfParticipants, total, currency, isDefaultUser =
* For example: if user1 owes user2 $10, then we have: {ownerAccountID: user2, managerID: user1, total: $10 (a positive amount, owed to user2)}
* If user1 requests $17 from user2, then we have: {ownerAccountID: user1, managerID: user2, total: $7 (still a positive amount, but now owed to user1)}
*
* @param {Object} iouReport
* @param {Number} actorAccountID
* @param {Number} amount
* @param {String} currency
* @param {String} isDeleting - whether the user is deleting the request
* @returns {Object}
* @param isDeleting - whether the user is deleting the request
*/
function updateIOUOwnerAndTotal(iouReport, actorAccountID, amount, currency, isDeleting = false) {
function updateIOUOwnerAndTotal(iouReport: Report, actorAccountID: number, amount: number, currency: string, isDeleting = false): Report {
if (currency !== iouReport.currency) {
return iouReport;
}

// Make a copy so we don't mutate the original object
const iouReportUpdate = {...iouReport};
const iouReportUpdate: Report = {...iouReport};

if (actorAccountID === iouReport.ownerAccountID) {
iouReportUpdate.total += isDeleting ? -amount : amount;
} else {
iouReportUpdate.total += isDeleting ? amount : -amount;
}
if (iouReportUpdate.total) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This line created a bug: Issue #33774

if (actorAccountID === iouReport.ownerAccountID) {
iouReportUpdate.total += isDeleting ? -amount : amount;
} else {
iouReportUpdate.total += isDeleting ? amount : -amount;
}

if (iouReportUpdate.total < 0) {
// The total sign has changed and hence we need to flip the manager and owner of the report.
iouReportUpdate.ownerAccountID = iouReport.managerID;
iouReportUpdate.managerID = iouReport.ownerAccountID;
iouReportUpdate.total = -iouReportUpdate.total;
}
if (iouReportUpdate.total < 0) {
// The total sign has changed and hence we need to flip the manager and owner of the report.
iouReportUpdate.ownerAccountID = iouReport.managerID;
iouReportUpdate.managerID = iouReport.ownerAccountID;
iouReportUpdate.total = -iouReportUpdate.total;
}

iouReportUpdate.hasOutstandingIOU = iouReportUpdate.total !== 0;
iouReportUpdate.hasOutstandingIOU = iouReportUpdate.total !== 0;
}

return iouReportUpdate;
}

/**
* Returns whether or not an IOU report contains money requests in a different currency
* that are either created or cancelled offline, and thus haven't been converted to the report's currency yet
*
* @param {Object} iouReport
* @returns {Boolean}
*/
function isIOUReportPendingCurrencyConversion(iouReport) {
const reportTransactions = TransactionUtils.getAllReportTransactions(iouReport.reportID);
const pendingRequestsInDifferentCurrency = _.filter(reportTransactions, (transaction) => transaction.pendingAction && TransactionUtils.getCurrency(transaction) !== iouReport.currency);
function isIOUReportPendingCurrencyConversion(iouReport: Report): boolean {
const reportTransactions: Transaction[] = TransactionUtils.getAllReportTransactions(iouReport.reportID);
const pendingRequestsInDifferentCurrency = reportTransactions.filter((transaction) => transaction.pendingAction && TransactionUtils.getCurrency(transaction) !== iouReport.currency);
return pendingRequestsInDifferentCurrency.length > 0;
}

/**
* Checks if the iou type is one of request, send, or split.
* @param {String} iouType
* @returns {Boolean}
*/
function isValidMoneyRequestType(iouType) {
return [CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT].includes(iouType);
function isValidMoneyRequestType(iouType: string): boolean {
const moneyRequestType: string[] = [CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT];
return moneyRequestType.includes(iouType);
}

export {calculateAmount, updateIOUOwnerAndTotal, isIOUReportPendingCurrencyConversion, isValidMoneyRequestType};
2 changes: 2 additions & 0 deletions src/types/onyx/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ type Report = {
lastActorAccountID?: number;
ownerAccountID?: number;
participantAccountIDs?: number[];
total?: number;
currency?: string;
};

export default Report;