commit 36f2b2784b4acc8ad6cd92e496e558babce5c9fe
parent 25347370d90aa453fb6016f5161a679623b9c03f
Author: Florian Dold <florian@dold.me>
Date: Thu, 16 Apr 2026 18:15:21 +0200
wallet-core: return haveProdBalance in getBalances
Diffstat:
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts
@@ -569,6 +569,8 @@ export interface DonauSummaryItem {
export interface BalancesResponse {
/** Electronic cash balances, per currency scope. */
balances: WalletBalance[];
+ /** Does the user have non-demo money? */
+ haveProdBalance: boolean;
/* Summary of donations, per donau/year/currency. */
donauSummary?: DonauSummaryItem[];
}
@@ -593,11 +595,6 @@ export const codecForBalance = (): Codec<WalletBalance> =>
.property("flags", codecForAny()) // FIXME
.build("Balance");
-export const codecForBalancesResponse = (): Codec<BalancesResponse> =>
- buildCodecForObject<BalancesResponse>()
- .property("balances", codecForList(codecForBalance()))
- .build("BalancesResponse");
-
/**
* For terseness.
*/
diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts
@@ -119,6 +119,7 @@ interface WalletBalance {
disablePeerPayments: boolean;
disableDirectDeposits: boolean;
shoppingUrls: Set<string>;
+ isProd: boolean;
}
function computeRefreshGroupAvailableAmountForExchanges(
@@ -171,6 +172,7 @@ function getScopeSortingOrder(scopeInfo: ScopeInfo): number {
}
class BalancesStore {
+ private nonDemoExchanges: Set<string> = new Set();
private exchangeScopeCache: Record<string, ScopeInfo> = {};
private balanceStore: Record<string, WalletBalance> = {};
private donauSummaryItems: DonauSummaryItem[] | undefined = undefined;
@@ -180,6 +182,10 @@ class BalancesStore {
private tx: WalletIndexedDbTransaction,
) {}
+ setNonDemoExchange(baseUrl: string) {
+ this.nonDemoExchanges.add(baseUrl);
+ }
+
/**
* Add amount to a balance field, both for
* the slicing by exchange and currency.
@@ -199,10 +205,10 @@ class BalancesStore {
this.exchangeScopeCache[exchangeBaseUrl] = scopeInfo;
}
const balanceKey = getBalanceKey(scopeInfo);
- const b = this.balanceStore[balanceKey];
+ let b = this.balanceStore[balanceKey];
if (!b) {
const zero = Amounts.zeroOfCurrency(currency);
- this.balanceStore[balanceKey] = {
+ b = this.balanceStore[balanceKey] = {
scopeInfo,
available: zero,
pendingIncoming: zero,
@@ -213,8 +219,10 @@ class BalancesStore {
disablePeerPayments: false,
disableDirectDeposits: false,
shoppingUrls: new Set(),
+ isProd: false,
};
}
+ b.isProd = b.isProd || this.nonDemoExchanges.has(exchangeBaseUrl);
return this.balanceStore[balanceKey];
}
@@ -317,6 +325,7 @@ class BalancesStore {
toBalancesResponse(): BalancesResponse {
const balancesResponse: BalancesResponse = {
balances: [],
+ haveProdBalance: false,
};
if (this.donauSummaryItems) {
@@ -364,6 +373,9 @@ class BalancesStore {
} else {
disablePeerPayments = v.disablePeerPayments;
}
+ if (Amounts.isNonZero(v.available) && v.isProd) {
+ balancesResponse.haveProdBalance = true;
+ }
balancesResponse.balances.push({
scopeInfo: v.scopeInfo,
available: Amounts.stringify(v.available),
@@ -404,6 +416,9 @@ export async function getBalancesInsideTransaction(
) {
const det = await getExchangeDetailsInTx(tx, ex.baseUrl);
if (det) {
+ if (ex.presetType == null || ex.presetType === "prod") {
+ balanceStore.setNonDemoExchange(ex.baseUrl);
+ }
await balanceStore.addZero(det.currency, ex.baseUrl);
if (ex.peerPaymentsDisabled) {
await balanceStore.setPeerPaymentsDisabled(det.currency, ex.baseUrl);