schlatt-co / stonks

Jschlatt sub server company management plugin
Apache License 2.0
3 stars 1 forks source link

Simultaneous payment problems #29

Closed JRoy closed 4 years ago

JRoy commented 4 years ago

There's issues with payment processing. Needs to be looked into

Tsarcasm commented 4 years ago

Found the cause

Tsarcasm commented 4 years ago

When you pay an account you do /stonks pay this opens a couple guis which are populated in advance

AccountSelectorGui.Builder accountSelectorScreen =
              new AccountSelectorGui.Builder()
                  .company(company)
                  .title("Select which account to pay")
                  .accountSelected(account -> {
                    String message = "Deposit"
                        + ((msg != null) ? " [message: \"" + msg + "\"]" : "");
                    payAccount(player, account, message, amount);
                  });

Which instantiates

private AccountSelectorGui(Company company, String title, Consumer<Account> onAccountSelected, Player player) {
    super(company.accounts, title);
    this.company = company;
    this.onAccountSelected = onAccountSelected;
  }

This is storing a collection of accounts, and also takes a consumer to handle when the account is selected. When this consumer is run it will be passed the account instance from when this was GUI was created.

If someone pays those accounts after the GUI is opened, the account instances in the GUI do not get updated with the new balance. So when this consumer is run, it has the incorrect balance.

account -> {
                    String message = "Deposit"
                        + ((msg != null) ? " [message: \"" + msg + "\"]" : "");
                    payAccount(player, account, message, amount);

^ This is the consumer passed to the account selector payAccount gets passed the potentially outdated account Repo.getInstance().payAccount(sender.getUniqueId(), message, account, amount); which calls this line ^ Again, passing the account In the repo, this happens

public Account payAccount(UUID player, String message, Account account, double amount) {
    ReturningAccountVisitor<Account> visitor = new ReturningAccountVisitor<>() {
      @Override
      public void visit(CompanyAccount a) {
        CompanyAccount ca = new CompanyAccount(a.pk, a.name, a.uuid, a.companyPk, a.services, a.balance + amount);
        companyAccountStore.save(ca);
        val = ca;
      }
CompanyAccount ca = new CompanyAccount(a.pk, a.name, a.uuid, a.companyPk, a.services, a.balance + amount);
companyAccountStore.save(ca);

This is our culprit line ^ We pass the outdated account into the visitor and save an account with the balance a.balance + amount boom thats the bug To fix it, we change the payAccount method to take an account pk instead of an instance

Tsarcasm commented 4 years ago

I'll add a note about this to tsorm too