taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

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:
Mpackages/taler-util/src/types-taler-wallet.ts | 7++-----
Mpackages/taler-wallet-core/src/balance.ts | 19+++++++++++++++++--
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);