diff --git a/realty-paper/src/main/java/io/github/md5sha256/realty/economy/TreasuryEconomyProvider.java b/realty-paper/src/main/java/io/github/md5sha256/realty/economy/TreasuryEconomyProvider.java index 1294cd9..28fa680 100644 --- a/realty-paper/src/main/java/io/github/md5sha256/realty/economy/TreasuryEconomyProvider.java +++ b/realty-paper/src/main/java/io/github/md5sha256/realty/economy/TreasuryEconomyProvider.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.List; import java.util.UUID; @@ -17,10 +18,11 @@ *
* Account resolution: the payer is always resolved as a personal account * (created with starting balance if missing). The recipient is resolved by - * preferring its PERSONAL account — rental/sale income belongs to the - * landlord personally, even if they happen to own a firm. Only when the - * recipient has no personal account (a synthetic authority UUID backing a - * government entity) do we fall back to a government/business account. + * preferring its GOVERNMENT account, then PERSONAL, then BUSINESS — so + * government landlords (legacy DCGovernment-style real UUIDs that own both a + * personal and a government account) route income to their government + * treasury, while ordinary landlords still get their personal balance rather + * than a firm BUSINESS account they happen to own. */ public final class TreasuryEconomyProvider implements EconomyProvider { @@ -47,10 +49,14 @@ public double getBalance(@NotNull UUID playerId) { try { Account payer = treasuryApi.resolveOrCreatePersonal(fromId); Account recipient = resolveRecipientAccount(toId); + // Treasury rejects amounts with more than 2 decimal places. Amounts + // derived from arithmetic (e.g. pro-rata refunds: price * remaining / + // total) can carry extra precision, so normalise to 2 decimals here. + BigDecimal normalisedAmount = BigDecimal.valueOf(amount).setScale(2, RoundingMode.HALF_UP); treasuryApi.transfer(new TransferRequest( payer.getAccountId(), recipient.getAccountId(), - BigDecimal.valueOf(amount), + normalisedAmount, ledgerMessage, fromId, null, @@ -74,27 +80,31 @@ public boolean hasLedgerSupport() { } /** - * Resolves the recipient's Treasury account. + * Resolves the recipient's Treasury account, preferring + * GOVERNMENT > PERSONAL > BUSINESS > first-available. *
- * A real player landlord always owns a PERSONAL account (Treasury enforces - * one per player), so we prefer it: their rental/sale income must land in - * their personal balance, never in a firm BUSINESS account they happen to - * own (firm accounts are owned by the proprietor's own UUID, which is how - * such funds previously leaked into business accounts). + * GOVERNMENT wins first because legacy government entities (e.g. + * DCGovernment) are real Minecraft accounts whose UUID owns both a + * personal and a government account; their leasehold income must land in + * the government treasury, not the player's personal balance. *
- * Only when the recipient has no personal account — i.e. a synthetic - * authority UUID that backs a government entity — do we fall back to the - * prior government > business > first-available ordering so authority - * payments still route to the configured government treasury account. + * Ordinary landlords have no government account, so PERSONAL is chosen next: + * rental/sale income belongs to them personally, never a firm BUSINESS + * account they happen to own (firm accounts are owned by the proprietor's + * own UUID, which is how such funds previously leaked into business + * accounts). + *
+ * When the recipient has no account at all, resolve-or-create their personal
+ * account.
*/
private @NotNull Account resolveRecipientAccount(@NotNull UUID ownerUuid) {
List