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] Review duplicates - Review duplicates button doesn’t disappear after deleting one expense #55138

Open
5 of 8 tasks
IuliiaHerets opened this issue Jan 12, 2025 · 20 comments
Assignees
Labels
Bug Something is broken. Auto assigns a BugZero manager. External Added to denote the issue can be worked on by a contributor Reviewing Has a PR in review Weekly KSv2

Comments

@IuliiaHerets
Copy link

IuliiaHerets commented Jan 12, 2025

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: v9.0.84-1
Reproducible in staging?: Yes
Reproducible in production?: Yes
Issue reported by: Applause Internal Team
Device used: Mac 15.2
App Component: Chat Report View

Action Performed:

  1. Navigate to https://staging.new.expensify.com
  2. Submit two identical expenses to the workspace chat
  3. Navigate to one of the expenses and delete it

Expected Result:

The review duplicates button should disappear after deleting one of the expenses

Actual Result:

The review duplicates button doesn’t disappear after deleting one of the expenses

Workaround:

Unknown

Platforms:

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

Screenshots/Videos

Bug6712538_1736704522689.Recording__400.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021880380172206780429
  • Upwork Job ID: 1880380172206780429
  • Last Price Increase: 2025-01-17
  • Automatic offers:
    • suneox | Reviewer | 105842696
    • Tony-MK | Contributor | 105842698
Issue OwnerCurrent Issue Owner: @suneox
@IuliiaHerets IuliiaHerets added Daily KSv2 Bug Something is broken. Auto assigns a BugZero manager. labels Jan 12, 2025
Copy link

melvin-bot bot commented Jan 12, 2025

Triggered auto assignment to @anmurali (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.

@Shahidullah-Muffakir
Copy link
Contributor

BE issue.

  1. when user deletes an expense with DeleteMoneyRequest, the BE only return the transactionViolations of the deleted transaction, not the other transactions.
  2. and the GetMissingOnyxMessages after DeleteMoneyRequest, is not returning the transactionViolations at all (only correcting this would solve the issue).
Screenshot 2025-01-13 at 3 08 05 AM

so when the OpenReport is called, it gets the updated transactionViolations.

@Tony-MK
Copy link
Contributor

Tony-MK commented Jan 13, 2025

🚨 Edited by proposal-police: This proposal was edited at 2025-01-19 08:14:29 UTC.

Proposal

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

Review duplicates button doesn’t disappear after deleting one expense

What is the root cause of that problem?

We are not deleting the transaction violations of the duplicate and only delete the transaction's violations.

App/src/libs/actions/IOU.ts

Lines 6117 to 6121 in c585eb9

optimisticData.push({
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
value: null,
});

Hence, the backend merges the valid transaction violations after OpenReport is called.

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

Let's optimistically, delete the duplicate transaction violations over here.

if (transactionViolations) {
    TransactionUtils.removeSettledAndApprovedTransactions(
        transactionViolations.find((violation) => violation?.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION)?.data?.duplicates ?? [],
    ).forEach((duplicateID) => {
        const duplicateTransactionsViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${duplicateID}`];
        if (!duplicateTransactionsViolations) {
            return;
        }

        const dulipcateViolation = duplicateTransactionsViolations.find((violation: OnyxTypes.TransactionViolation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION);

        if (!dulipcateViolation?.data?.duplicates) {
            return;
        }

        const duplicateTransactionIDs = dulipcateViolation.data.duplicates.filter((duplicateTransactionID) => duplicateTransactionID !== transactionID);

        optimisticData.push({
            onyxMethod: Onyx.METHOD.SET,
            key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${duplicateID}`,
            value:
                duplicateTransactionIDs.length === 0
                    ? duplicateTransactionsViolations.filter((violation: OnyxTypes.TransactionViolation) => violation.name !== CONST.VIOLATIONS.DUPLICATED_TRANSACTION)
                    : [
                          ...duplicateTransactionsViolations.filter((violation: OnyxTypes.TransactionViolation) => violation.name !== CONST.VIOLATIONS.DUPLICATED_TRANSACTION),
                          {
                              ...dulipcateViolation,
                              data: {
                                  ...dulipcateViolation.data,
                                  duplicates: duplicateTransactionIDs,
                              },
                          },
                      ],
        });

        failureData.push({
            onyxMethod: Onyx.METHOD.SET,
            key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${duplicateID}`,
            value: duplicateTransactionsViolations,
        });
    });
}

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

Currently, in the IOUTest.ts, we don't test transactions that have violations.

Hence, we should create the test transactions and then test the optimistic output of the deleteMoneyRequest function.

@melvin-bot melvin-bot bot added the Overdue label Jan 15, 2025
Copy link

melvin-bot bot commented Jan 16, 2025

@anmurali Whoops! This issue is 2 days overdue. Let's get this updated quick!

@anmurali anmurali added the External Added to denote the issue can be worked on by a contributor label Jan 17, 2025
@melvin-bot melvin-bot bot changed the title Review duplicates - Review duplicates button doesn’t disappear after deleting one expense [$250] Review duplicates - Review duplicates button doesn’t disappear after deleting one expense Jan 17, 2025
Copy link

melvin-bot bot commented Jan 17, 2025

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

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label Jan 17, 2025
Copy link

melvin-bot bot commented Jan 17, 2025

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

@suneox
Copy link
Contributor

suneox commented Jan 19, 2025

@Tony-MK Thank you for your proposal. However, we need to build the optimistic/failure data for the related duplicate transactions, not only simply find all and get the first item.
We're still looking for a proposal on this one.

@Tony-MK
Copy link
Contributor

Tony-MK commented Jan 19, 2025

Proposal

Hey @suneox, I updated my propsal.

Can you review it again?

@garrettmknight garrettmknight moved this to Bugs and Follow Up Issues in [#whatsnext] #expense Jan 21, 2025
Copy link

melvin-bot bot commented Jan 22, 2025

@suneox, @anmurali Whoops! This issue is 2 days overdue. Let's get this updated quick!

@melvin-bot melvin-bot bot added the Overdue label Jan 22, 2025
@anmurali
Copy link

@suneox bump on Tony's revised proposal?

@anmurali anmurali added Daily KSv2 and removed Daily KSv2 Overdue labels Jan 22, 2025
@suneox
Copy link
Contributor

suneox commented Jan 22, 2025

However, we need to build the optimistic/failure data for the related duplicate transactions

@Tony-MK Your update still doesn't resolve the issue with the related duplicate transactions.

Image

@huult
Copy link
Contributor

huult commented Jan 22, 2025

🚨 Edited by proposal-police: This proposal was edited at 2025-01-23 02:57:57 UTC.

Proposal

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

Review duplicates button doesn’t disappear after deleting one expense

What is the root cause of that problem?

We only check for duplicates by the violation name.

const hasDuplicatedViolation = !!allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]?.some(

And when we DeleteMoneyRequest, the transaction will be removed. However, the transactionViolations of the last duplicate will not be removed, causing this issue

  • Image

Describe the image above:

4174082169539691044 is the transaction that was removed (DeleteMoneyRequest)

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

To resolve this issue, the condition for hasDuplicatedViolation must be updated to check if the transaction exists and violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION. If both conditions are met, it is marked as having a duplicate; otherwise, it is not.

const hasDuplicatedViolation = !!allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]?.some(

Update to:

   const duplicates =
        allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]?.find((violation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION)?.data
            ?.duplicates ?? [];
    const hasDuplicatedViolation = !!allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]?.some(
        (violation: TransactionViolation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION && !!duplicates.map((item) => getTransaction(item)).filter((item) => !!item).length,
    );

Or, if we want to return early, then:

function isDuplicate(transactionID: string | undefined, checkDismissed = false): boolean {

   const duplicates =
        allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]?.find((violation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION)?.data
            ?.duplicates ?? [];
    const transactions = duplicates.map((item) => getTransaction(item)).filter((item) => !!item);
    if (!transactions.length) {
        return false;
    }

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

We need to update the isDuplicate test to return false if the transaction does not exist.

What alternative solutions did you explore? (Optional)

Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.

We can fix this issue by removing TRANSACTION_VIOLATIONS if it is the last duplicate, something like this:

add:

    const duplicates =
        allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]?.find((violation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION)?.data
            ?.duplicates ?? [];
    const transactionViolationsDuplicates = duplicates.map((item) => {
        const violations = getTransactionViolations(item, allTransactionViolations);

        // Filter and update violations
        const filteredViolations =
            violations?.map((violation) => {
                if (violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION) {
                    const updatedDuplicates = violation.data?.duplicates?.filter((id) => id !== transactionID);

                    if (!updatedDuplicates?.length) {
                        return null;
                    }

                    return {
                        ...violation,
                        data: {
                            ...violation.data,
                            duplicates: updatedDuplicates,
                        },
                    };
                }

                return violation;
            }) ?? [];
        return {transactionID: item, data: filteredViolations.filter((item) => !!item)};
    });

    transactionViolationsDuplicates.forEach((item) => {
        optimisticData.push({
            onyxMethod: Onyx.METHOD.SET,
            key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${item.transactionID}`,
            value: item.data.length ? item.data : null,
        });
    });

We should also remove it in case of failure:

add:

    transactionViolationsDuplicates.forEach((item) => {
        failureData.push({
            onyxMethod: Onyx.METHOD.SET,
            key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${item.transactionID}`,
            value: item.data.length ? item.data : null,
        });
    });
POC
Screen.Recording.2025-01-23.at.09.56.11.mp4

Test branch

@huult
Copy link
Contributor

huult commented Jan 23, 2025

Proposal updated

  • Added an alternative solution

@suneox Could you please review my proposal when you have time? Thank you

@Tony-MK
Copy link
Contributor

Tony-MK commented Jan 23, 2025

Proposal

Hey @suneox, I updated my propsal.

It's clearer to explain how to delete the money if there is more than one duplicate transaction.

Could you review it?

Thanks

@suneox
Copy link
Contributor

suneox commented Jan 24, 2025

Thank you for all the updates. The solutions from @huult and @Tony-MK still work when handling optimistic data in the case of removing expenses with multiple duplicated transaction violations. However, the alternative solution from @huult, which handles failureData the same as optimistic data, is incorrect. Therefore, we can proceed with @Tony-MK proposal, and the code lint from selected proposal can be performed during the code review.

🎀 👀 🎀 C+ reviewed

Copy link

melvin-bot bot commented Jan 24, 2025

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

@melvin-bot melvin-bot bot removed the Help Wanted Apply this label when an issue is open to proposals by contributors label Jan 24, 2025
Copy link

melvin-bot bot commented Jan 24, 2025

📣 @suneox 🎉 An offer has been automatically sent to your Upwork account for the Reviewer role 🎉 Thanks for contributing to the Expensify app!

Offer link
Upwork job

Copy link

melvin-bot bot commented Jan 24, 2025

📣 @Tony-MK 🎉 An offer has been automatically sent to your Upwork account for the Contributor role 🎉 Thanks for contributing to the Expensify app!

Offer link
Upwork job
Please accept the offer and leave a comment on the Github issue letting us know when we can expect a PR to be ready for review 🧑‍💻
Keep in mind: Code of Conduct | Contributing 📖

Copy link

melvin-bot bot commented Jan 26, 2025

@Julesssss @suneox @anmurali @Tony-MK 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!

@Tony-MK
Copy link
Contributor

Tony-MK commented Jan 27, 2025

Hi @suneox, the PR is ready for review.

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. External Added to denote the issue can be worked on by a contributor Reviewing Has a PR in review Weekly KSv2
Projects
Status: Bugs and Follow Up Issues
Development

No branches or pull requests

7 participants