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

[$250] Search-Invoice with +2 expense submitted in OD is displayed with a negative total amount in ND #53045

Open
4 of 8 tasks
IuliiaHerets opened this issue Nov 24, 2024 · 30 comments
Assignees
Labels
Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 External Added to denote the issue can be worked on by a contributor Help Wanted Apply this label when an issue is open to proposals by contributors

Comments

@IuliiaHerets
Copy link

IuliiaHerets commented Nov 24, 2024

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Version Number: 9.0.66-0
Reproducible in staging?: Y
Reproducible in production?: Y
If this was caught during regression testing, add the test name, ID and link from TestRail: https://expensify.testrail.io/index.php?/tests/view/5256232
Issue reported by: Applause Internal Team

Action Performed:

  1. Login with a account that is an admin of a workspace
  2. Login with the same account in OD
  3. In OD - Submit a invoice to anyone with at least 2 expenses
  4. Back in ND - Navigate to the Search page
  5. Click on invoices
  6. Click on the Outstanding filter
  7. Verify the expenses are now divided per invoice report
  8. Verify the invoice submitted in OD has the 2 expenses grouped

Expected Result:

The invoice with at least 2 expenses submitted in OD is displayed with a positive total amount in ND.

Actual Result:

The invoice with at least 2 expenses submitted in OD is displayed with a negative total amount in ND.

Workaround:

Unknown

Platforms:

  • Android: Standalone
  • Android: HybridApp
  • Android: mWeb Chrome
  • iOS: Standalone
  • iOS: HybridApp
  • iOS: mWeb Safari
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

Bug6674480_1732394559440!total_negative_amount

Bug6674480_1732394559495.total_negative_amount.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021861216736472283553
  • Upwork Job ID: 1861216736472283553
  • Last Price Increase: 2024-12-10
Issue OwnerCurrent Issue Owner: @ikevin127
@IuliiaHerets IuliiaHerets added Daily KSv2 Bug Something is broken. Auto assigns a BugZero manager. labels Nov 24, 2024
Copy link

melvin-bot bot commented Nov 24, 2024

Triggered auto assignment to @mallenexpensify (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

@bernhardoj
Copy link
Contributor

bernhardoj commented Nov 25, 2024

Edited by proposal-police: This proposal was edited at 2024-11-28 02:32:31 UTC.

Proposal

Please re-state the problem that we are trying to solve in this issue.

The total invoice report amount is shown in negative.

What is the root cause of that problem?

The total amount of the invoice report is in negative, the same as expense report. However, when we show the total amount, we only negate the expense report.

let total = reportItem?.total ?? 0;
// Only invert non-zero values otherwise we'll end up with -0.00
if (total) {
total *= reportItem?.type === CONST.REPORT.TYPE.EXPENSE ? -1 : 1;
}

So, for invoice report, the negative amount is shown.

What changes do you think we should make in order to solve the problem?

We need to check for invoice type too and if it's true, then we negate it too (multiply by -1)

total *= (reportItem?.type === CONST.REPORT.TYPE.EXPENSE || reportItem?.type === CONST.REPORT.TYPE.INVOICE) ? -1 : 1;

OR

total *= (isExpenseReport(reportItem) || isInvoiceReport(reportItem)) ? -1 : 1;

(or we can use Math.abs if it's not an expense report)

There are multiple places where we check for expense report type to multiply it by -1 where we can probably apply the same fix, but looks like it's currently not possible to view an invoice report, so not sure how to test the other cases. To handle the other cases too, we can create a new util function in IOUUtils called getNormalizedAmount.

function getNormalizedAmount(amount: number, report: Report) {
    // Only invert non-zero values otherwise we'll end up with -0.00
    if (!amount) {
        return amount;
    }

    // Expense and invoice report case:
    // The amounts are stored using an opposite sign and negative values can be set,
    // we need to return an opposite sign
    if (isExpenseReport(report) || isInvoiceReport(report)) {
        return -amount;
    }

    // IOU requests cannot have negative values, but they can be stored as negative values, let's return absolute value
    return Math.abs(amount);
}

And then we can use it like this

let total = reportItem?.total ?? 0;
// Only invert non-zero values otherwise we'll end up with -0.00
if (total) {
total *= reportItem?.type === CONST.REPORT.TYPE.EXPENSE ? -1 : 1;
}

const total = IOUUtils.getNormalizedAmount(reportItem?.total ?? 0, reportItem);

@mallenexpensify mallenexpensify added the External Added to denote the issue can be worked on by a contributor label Nov 26, 2024
@melvin-bot melvin-bot bot changed the title Search-Invoice with +2 expense submitted in OD is displayed with a negative total amount in ND [$250] Search-Invoice with +2 expense submitted in OD is displayed with a negative total amount in ND Nov 26, 2024
Copy link

melvin-bot bot commented Nov 26, 2024

Job added to Upwork: https://www.upwork.com/jobs/~021861216736472283553

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label Nov 26, 2024
Copy link

melvin-bot bot commented Nov 26, 2024

Triggered auto assignment to Contributor-plus team member for initial proposal review - @ikevin127 (External)

@mallenexpensify
Copy link
Contributor

There are multiple places where we check for expense report type to multiply it by -1 where we can probably apply the same fix,

Music to my ears @bernhardoj :)

Was able to reproduce
SnagitHelper2024 2024-11-25 17 13 16

When I click on View I get an error, is that also related here?
SnagitHelper2024 2024-11-25 17 13 32

Google Chrome 2024-11-25 17 13 24

Only error I see in console
image

@bernhardoj
Copy link
Contributor

The BE returns not found error when viewing it.
image

@ikevin127
Copy link
Contributor

Let's go with @bernhardoj's proposal since the RCA makes sense and the proposed solution fixes the issue.

Regarding the solution, since the component already imports ReportUtils, I like this version as it's 14 characters shorter:

total *= ReportUtils.isExpenseReport(reportItem) || ReportUtils.isInvoiceReport(reportItem) ? -1 : 1;

🎀👀🎀 C+ reviewed

When I click on View I get an error, is that also related here ?

I don't see it related to the negative amount issue in any way which would justify extending the scope of this issue given the context shared in #53045 (comment) - I think it should be treated as a separate issue.

Copy link

melvin-bot bot commented Nov 26, 2024

Triggered auto assignment to @iwiznia, see https://stackoverflow.com/c/expensify/questions/7972 for more details.

@iwiznia
Copy link
Contributor

iwiznia commented Nov 26, 2024

Anyone knows why we invert the amount for expense (and now invoice) but not other types?

Solution sounds good, but it seems like we should centralize this logic in one function so we don't have the same bug in many places and try to find all places where this logic exists... I see for example we have it also here

Can you update the proposal to include that please?

@bernhardoj
Copy link
Contributor

It's explained here (invoice not included)

function getAmount(transaction: OnyxInputOrEntry<Transaction>, isFromExpenseReport = false, isFromTrackedExpense = false): number {
// IOU requests cannot have negative values, but they can be stored as negative values, let's return absolute value
if (!isFromExpenseReport || isFromTrackedExpense) {
const amount = transaction?.modifiedAmount ?? 0;
if (amount) {
return Math.abs(amount);
}
return Math.abs(transaction?.amount ?? 0);
}
// Expense report case:
// The amounts are stored using an opposite sign and negative values can be set,
// we need to return an opposite sign than is saved in the transaction object
let amount = transaction?.modifiedAmount ?? 0;
if (amount) {
return -amount;
}
// To avoid -0 being shown, lets only change the sign if the value is other than 0.
amount = transaction?.amount ?? 0;
return amount ? -amount : 0;
}

I think we can create a util function in IOUUtils called getNormalizedAmount, but do we want to follow the logic above, that is multiply by -1 for the expense report only and use abs for the invoice?

@iwiznia
Copy link
Contributor

iwiznia commented Nov 26, 2024

Ah nice, let's ensure we have that explanation in the new method and that we use it there too as it seems that code is also wrong

@iwiznia
Copy link
Contributor

iwiznia commented Nov 26, 2024

I think we can create a util function in IOUUtils called getNormalizedAmount, but do we want to follow the logic above, that is multiply by -1 for the expense report only and use abs for the invoice?

I don't think so, invoices can be positive or negative, same as expense reports. IOUs are the only ones that are different

@bernhardoj
Copy link
Contributor

Updated my proposal to include the util function.

as it seems that code is also wrong

Which part of TransactionUtils.getAmount is wrong?

@iwiznia
Copy link
Contributor

iwiznia commented Nov 28, 2024

Actually not sure if it is wrong, because I now realize I have no idea what isFromTrackedExpense means (let's add a comment on the param as part of this change once we figure it out). I was thinking it is not checking invoices there, so it might be using the abs version instead of the negated version.

@melvin-bot melvin-bot bot added the Overdue label Nov 28, 2024
@bernhardoj
Copy link
Contributor

My first thought that it should be true for self DM track, but I just realized we can track expense in workspace too. It was added in #38709, specifically this commit, but looks like we never make use of the isFromTrackedExpense param in that PR, meaning it's always false.

The only code that uses it is this:

const taxAmount = getTaxAmount(policy, currentTransaction, taxes.code, TransactionUtils.getAmount(currentTransaction, false, true));

It's from this PR: #40443

Maybe @ishpaul777 can help us clarify the purpose of that param.

@iwiznia
Copy link
Contributor

iwiznia commented Nov 28, 2024

ccing @thienlnam too since he was reviewer of #38709

Copy link

melvin-bot bot commented Nov 29, 2024

@iwiznia, @mallenexpensify, @ikevin127 Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

@iwiznia
Copy link
Contributor

iwiznia commented Nov 29, 2024

Waiting on input from the people pinged above

@ikevin127
Copy link
Contributor

Waiting on input from the people pinged above

@melvin-bot melvin-bot bot removed the Overdue label Nov 29, 2024
@ishpaul777
Copy link
Contributor

From the blame history, I recall initially being confused about how tracked expenses should be moved to the workspace chat. In self-DM, tracked expenses were stored as negative values. When moving them to the workspace, I converted them to +ive.

At that time, I added this check. However, after i was corrected by Jack, I removed the parameter locally. Unfortunately, I believe I missed removing the parameter from the function during cleanup, which was an oversight.

As for why the param is used later, I don't have much context, but it appears to be related to this commit: 228c47705cc4a06d8d0a343be222e8e952523039.

Copy link

melvin-bot bot commented Dec 3, 2024

@iwiznia, @mallenexpensify, @ikevin127 Whoops! This issue is 2 days overdue. Let's get this updated quick!

@melvin-bot melvin-bot bot added the Overdue label Dec 3, 2024
Copy link

melvin-bot bot commented Dec 3, 2024

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

@ikevin127
Copy link
Contributor

Still working on a decision regarding the direction of this issue and its fix.

@mallenexpensify
Copy link
Contributor

@thienlnam 👀 above plz cuz you were the reviewier on the PR below.

we can track expense in workspace too. It was added in #38709,

@thienlnam
Copy link
Contributor

Could someone summarize what the confusion is regarding?

If it's about the isFromTrackedExpense param, it's been a while but my guess is from when you convert a tracked expense to a reimbursable one since we flip the amount (negative to positive). If it's not used anymore, let's just remove it

@melvin-bot melvin-bot bot added the Overdue label Dec 6, 2024
@bernhardoj
Copy link
Contributor

Yes, it's the isFromTrackedExpense param, but we have one usage of it on the IOU tax rate page.

const taxAmount = getTaxAmount(policy, currentTransaction, taxes.code, TransactionUtils.getAmount(currentTransaction, false, true));

From this commit, previously we get the transaction amount by transaction.amount to calculate the tax amount. That PR updates it to use TransactionUtils.getAmount most likely to cover the case when the amount is updated, thus we should get from transaction.modifiedAmount instead (which what TransactionUtils.getAmount does).

My guess with why we pass isFromTrackedExpense as true and isFromExpenseReport as false is so that the amount returned is always in positive.

// IOU requests cannot have negative values, but they can be stored as negative values, let's return absolute value
if (!isFromExpenseReport || isFromTrackedExpense) {
const amount = transaction?.modifiedAmount ?? 0;
if (amount) {
return Math.abs(amount);
}
return Math.abs(transaction?.amount ?? 0);
}

I think we can safely remove isFromTrackedExpense. @iwiznia What do you think?

@ikevin127
Copy link
Contributor

Not overdue - still discussing.

@melvin-bot melvin-bot bot removed the Overdue label Dec 6, 2024
Copy link

melvin-bot bot commented Dec 8, 2024

@iwiznia @mallenexpensify @ikevin127 this issue was created 2 weeks ago. Are we close to approving a proposal? If not, what's blocking us from getting this issue assigned? Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!

@melvin-bot melvin-bot bot added the Overdue label Dec 8, 2024
@ikevin127
Copy link
Contributor

Not overdue - still discussing.

@melvin-bot melvin-bot bot removed the Overdue label Dec 9, 2024
Copy link

melvin-bot bot commented Dec 10, 2024

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 External Added to denote the issue can be worked on by a contributor Help Wanted Apply this label when an issue is open to proposals by contributors
Projects
Status: No status
Development

No branches or pull requests

7 participants