introducing getBalanceDetail for getting all depositable/transferable amount for a currency
This commit is contained in:
parent
81dda3b6b1
commit
7ea8321ddd
@ -105,6 +105,16 @@ export class CreateReserveResponse {
|
||||
reservePub: string;
|
||||
}
|
||||
|
||||
export interface GetBalanceDetailRequest {
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export const codecForGetBalanceDetailRequest = (): Codec<GetBalanceDetailRequest> =>
|
||||
buildCodecForObject<GetBalanceDetailRequest>()
|
||||
.property("currency", codecForString())
|
||||
.build("GetBalanceDetailRequest");
|
||||
|
||||
|
||||
export interface Balance {
|
||||
available: AmountString;
|
||||
pendingIncoming: AmountString;
|
||||
@ -215,11 +225,11 @@ export interface CoinDumpJson {
|
||||
withdrawal_reserve_pub: string | undefined;
|
||||
coin_status: CoinStatus;
|
||||
spend_allocation:
|
||||
| {
|
||||
id: string;
|
||||
amount: string;
|
||||
}
|
||||
| undefined;
|
||||
| {
|
||||
id: string;
|
||||
amount: string;
|
||||
}
|
||||
| undefined;
|
||||
/**
|
||||
* Information about the age restriction
|
||||
*/
|
||||
@ -1792,6 +1802,7 @@ export const codecForUserAttentionsRequest = (): Codec<UserAttentionsRequest> =>
|
||||
)
|
||||
.build("UserAttentionsRequest");
|
||||
|
||||
|
||||
export interface UserAttentionsRequest {
|
||||
priority?: AttentionPriority;
|
||||
}
|
||||
|
@ -48,14 +48,12 @@
|
||||
*/
|
||||
import {
|
||||
AmountJson,
|
||||
BalancesResponse,
|
||||
Amounts,
|
||||
Logger,
|
||||
AuditorHandle,
|
||||
ExchangeHandle,
|
||||
BalancesResponse,
|
||||
canonicalizeBaseUrl,
|
||||
GetBalanceDetailRequest,
|
||||
Logger,
|
||||
parsePaytoUri,
|
||||
TalerErrorCode,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import {
|
||||
AllowedAuditorInfo,
|
||||
@ -63,11 +61,10 @@ import {
|
||||
RefreshGroupRecord,
|
||||
WalletStoresV1,
|
||||
} from "../db.js";
|
||||
import { GetReadOnlyAccess } from "../util/query.js";
|
||||
import { InternalWalletState } from "../internal-wallet-state.js";
|
||||
import { getExchangeDetails } from "./exchanges.js";
|
||||
import { checkLogicInvariant } from "../util/invariants.js";
|
||||
import { TalerError } from "../errors.js";
|
||||
import { GetReadOnlyAccess } from "../util/query.js";
|
||||
import { getExchangeDetails } from "./exchanges.js";
|
||||
|
||||
/**
|
||||
* Logger.
|
||||
@ -429,6 +426,43 @@ export async function getMerchantPaymentBalanceDetails(
|
||||
return d;
|
||||
}
|
||||
|
||||
export async function getBalanceDetail(
|
||||
ws: InternalWalletState,
|
||||
req: GetBalanceDetailRequest,
|
||||
): Promise<MerchantPaymentBalanceDetails> {
|
||||
const exchanges: { exchangeBaseUrl: string; exchangePub: string }[] = [];
|
||||
const wires = new Array<string>();
|
||||
await ws.db
|
||||
.mktx((x) => [x.exchanges, x.exchangeDetails])
|
||||
.runReadOnly(async (tx) => {
|
||||
const allExchanges = await tx.exchanges.iter().toArray();
|
||||
for (const e of allExchanges) {
|
||||
const details = await getExchangeDetails(tx, e.baseUrl);
|
||||
if (!details || req.currency !== details.currency) {
|
||||
continue;
|
||||
}
|
||||
details.wireInfo.accounts.forEach((a) => {
|
||||
const payto = parsePaytoUri(a.payto_uri);
|
||||
if (payto && !wires.includes(payto.targetType)) {
|
||||
wires.push(payto.targetType);
|
||||
}
|
||||
});
|
||||
exchanges.push({
|
||||
exchangePub: details.masterPublicKey,
|
||||
exchangeBaseUrl: e.baseUrl,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return await getMerchantPaymentBalanceDetails(ws, {
|
||||
currency: req.currency,
|
||||
acceptedAuditors: [],
|
||||
acceptedExchanges: exchanges,
|
||||
acceptedWireMethods: wires,
|
||||
minAge: 0,
|
||||
});
|
||||
}
|
||||
|
||||
export interface PeerPaymentRestrictionsForBalance {
|
||||
currency: string;
|
||||
restrictExchangeTo?: string;
|
||||
|
@ -457,7 +457,6 @@ export async function prepareDepositGroup(
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export async function createDepositGroup(
|
||||
ws: InternalWalletState,
|
||||
req: CreateDepositGroupRequest,
|
||||
|
@ -24,7 +24,7 @@
|
||||
* Imports.
|
||||
*/
|
||||
import {
|
||||
AbortTransactionRequest as AbortTransactionRequest,
|
||||
AbortTransactionRequest,
|
||||
AcceptBankIntegratedWithdrawalRequest,
|
||||
AcceptExchangeTosRequest,
|
||||
AcceptManualWithdrawalRequest,
|
||||
@ -56,6 +56,7 @@ import {
|
||||
ExchangesListResponse,
|
||||
ForceRefreshRequest,
|
||||
ForgetKnownBankAccountsRequest,
|
||||
GetBalanceDetailRequest,
|
||||
GetContractTermsDetailsRequest,
|
||||
GetExchangeTosRequest,
|
||||
GetExchangeTosResult,
|
||||
@ -66,14 +67,12 @@ import {
|
||||
InitiatePeerPullPaymentResponse,
|
||||
InitiatePeerPushPaymentRequest,
|
||||
InitiatePeerPushPaymentResponse,
|
||||
InitRequest,
|
||||
InitResponse,
|
||||
IntegrationTestArgs,
|
||||
KnownBankAccounts,
|
||||
ListKnownBankAccountsRequest,
|
||||
ManualWithdrawalDetails,
|
||||
UserAttentionsCountResponse,
|
||||
UserAttentionsRequest,
|
||||
UserAttentionsResponse,
|
||||
PrepareDepositRequest,
|
||||
PrepareDepositResponse,
|
||||
PreparePayRequest,
|
||||
@ -99,14 +98,16 @@ import {
|
||||
TransactionByIdRequest,
|
||||
TransactionsRequest,
|
||||
TransactionsResponse,
|
||||
UserAttentionByIdRequest,
|
||||
UserAttentionsCountResponse,
|
||||
UserAttentionsRequest,
|
||||
UserAttentionsResponse,
|
||||
WalletBackupContentV1,
|
||||
WalletCoreVersion,
|
||||
WalletCurrencyInfo,
|
||||
WithdrawFakebankRequest,
|
||||
WithdrawTestBalanceRequest,
|
||||
WithdrawUriInfoResponse,
|
||||
UserAttentionByIdRequest,
|
||||
InitRequest,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { WalletContractData } from "./db.js";
|
||||
import {
|
||||
@ -116,6 +117,7 @@ import {
|
||||
RemoveBackupProviderRequest,
|
||||
RunBackupCycleRequest,
|
||||
} from "./operations/backup/index.js";
|
||||
import { MerchantPaymentBalanceDetails } from "./operations/balance.js";
|
||||
import { PendingOperationsResponse as PendingTasksResponse } from "./pending-types.js";
|
||||
|
||||
export enum WalletApiOperation {
|
||||
@ -138,6 +140,7 @@ export enum WalletApiOperation {
|
||||
GetWithdrawalDetailsForAmount = "getWithdrawalDetailsForAmount",
|
||||
AcceptManualWithdrawal = "acceptManualWithdrawal",
|
||||
GetBalances = "getBalances",
|
||||
GetBalanceDetail = "getBalanceDetail",
|
||||
GetUserAttentionRequests = "getUserAttentionRequests",
|
||||
GetUserAttentionUnreadCount = "getUserAttentionUnreadCount",
|
||||
MarkAttentionRequestAsRead = "markAttentionRequestAsRead",
|
||||
@ -221,6 +224,11 @@ export type GetBalancesOp = {
|
||||
request: EmptyObject;
|
||||
response: BalancesResponse;
|
||||
};
|
||||
export type GetBalancesDetailOp = {
|
||||
op: WalletApiOperation.GetBalanceDetail;
|
||||
request: GetBalanceDetailRequest;
|
||||
response: MerchantPaymentBalanceDetails;
|
||||
};
|
||||
|
||||
// group: Managing Transactions
|
||||
|
||||
@ -831,6 +839,7 @@ export type WalletOperations = {
|
||||
[WalletApiOperation.ConfirmPay]: ConfirmPayOp;
|
||||
[WalletApiOperation.AbortTransaction]: AbortTransactionOp;
|
||||
[WalletApiOperation.GetBalances]: GetBalancesOp;
|
||||
[WalletApiOperation.GetBalanceDetail]: GetBalancesDetailOp;
|
||||
[WalletApiOperation.GetTransactions]: GetTransactionsOp;
|
||||
[WalletApiOperation.GetTransactionById]: GetTransactionByIdOp;
|
||||
[WalletApiOperation.RetryPendingNow]: RetryPendingNowOp;
|
||||
|
@ -45,6 +45,7 @@ import {
|
||||
codecForDeleteTransactionRequest,
|
||||
codecForForceRefreshRequest,
|
||||
codecForForgetKnownBankAccounts,
|
||||
codecForGetBalanceDetailRequest,
|
||||
codecForGetContractTermsDetails,
|
||||
codecForGetExchangeTosRequest,
|
||||
codecForGetFeeForDeposit,
|
||||
@ -87,6 +88,7 @@ import {
|
||||
ExchangesListResponse,
|
||||
ExchangeTosStatusDetails,
|
||||
FeeDescription,
|
||||
GetBalanceDetailRequest,
|
||||
GetExchangeTosResult,
|
||||
InitResponse,
|
||||
j2s,
|
||||
@ -154,7 +156,11 @@ import {
|
||||
runBackupCycle,
|
||||
} from "./operations/backup/index.js";
|
||||
import { setWalletDeviceId } from "./operations/backup/state.js";
|
||||
import { getBalances } from "./operations/balance.js";
|
||||
import {
|
||||
getBalanceDetail,
|
||||
getBalances,
|
||||
getMerchantPaymentBalanceDetails,
|
||||
} from "./operations/balance.js";
|
||||
import {
|
||||
getExchangeTosStatus,
|
||||
makeExchangeListItem,
|
||||
@ -948,9 +954,9 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> {
|
||||
ageCommitmentProof: c.ageCommitmentProof,
|
||||
spend_allocation: c.spendAllocation
|
||||
? {
|
||||
amount: c.spendAllocation.amount,
|
||||
id: c.spendAllocation.id,
|
||||
}
|
||||
amount: c.spendAllocation.amount,
|
||||
id: c.spendAllocation.id,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
@ -1111,6 +1117,10 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
|
||||
case WalletApiOperation.GetBalances: {
|
||||
return await getBalances(ws);
|
||||
}
|
||||
case WalletApiOperation.GetBalanceDetail: {
|
||||
const req = codecForGetBalanceDetailRequest().decode(payload);
|
||||
return await getBalanceDetail(ws, req);
|
||||
}
|
||||
case WalletApiOperation.GetUserAttentionRequests: {
|
||||
const req = codecForUserAttentionsRequest().decode(payload);
|
||||
return await getUserAttentions(ws, req);
|
||||
@ -1350,7 +1360,8 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
|
||||
{
|
||||
amount: Amounts.stringify(amount),
|
||||
reserve_pub: wres.reservePub,
|
||||
debit_account: "payto://x-taler-bank/localhost/testdebtor?receiver-name=Foo",
|
||||
debit_account:
|
||||
"payto://x-taler-bank/localhost/testdebtor?receiver-name=Foo",
|
||||
},
|
||||
);
|
||||
const fbResp = await readSuccessResponseJsonOrThrow(fbReq, codecForAny());
|
||||
|
@ -66,6 +66,7 @@ export namespace State {
|
||||
error: undefined;
|
||||
type: Props["type"];
|
||||
selectCurrency: ButtonHandler;
|
||||
sendAll: ButtonHandler;
|
||||
previous: Contact[];
|
||||
goToBank: ButtonHandler;
|
||||
goToWallet: ButtonHandler;
|
||||
|
@ -27,10 +27,21 @@ import { Contact, Props, State } from "./index.js";
|
||||
export function useComponentState(props: Props): RecursiveState<State> {
|
||||
const api = useBackendContext();
|
||||
const { pushAlertOnError } = useAlertContext();
|
||||
|
||||
const parsedInitialAmount = !props.amount
|
||||
? undefined
|
||||
: Amounts.parse(props.amount);
|
||||
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
if (!parsedInitialAmount) return undefined;
|
||||
const resp = await api.wallet.call(WalletApiOperation.GetBalanceDetail, {
|
||||
currency: parsedInitialAmount.currency,
|
||||
});
|
||||
return resp;
|
||||
});
|
||||
|
||||
const total = hook && !hook.hasError ? hook.response : undefined;
|
||||
|
||||
// const initialCurrency = parsedInitialAmount?.currency;
|
||||
|
||||
const [amount, setAmount] = useState(
|
||||
@ -120,6 +131,14 @@ export function useComponentState(props: Props): RecursiveState<State> {
|
||||
props.goToWalletBankDeposit(currencyAndAmount);
|
||||
}),
|
||||
},
|
||||
sendAll: {
|
||||
onClick:
|
||||
total === undefined
|
||||
? undefined
|
||||
: pushAlertOnError(async () => {
|
||||
setAmount(total.balanceMerchantDepositable);
|
||||
}),
|
||||
},
|
||||
goToWallet: {
|
||||
onClick: invalid
|
||||
? undefined
|
||||
@ -143,6 +162,7 @@ export function useComponentState(props: Props): RecursiveState<State> {
|
||||
setAmount(undefined);
|
||||
}),
|
||||
},
|
||||
sendAll: {},
|
||||
goToBank: {
|
||||
onClick: invalid
|
||||
? undefined
|
||||
|
@ -35,6 +35,7 @@ export const GetCash = tests.createExample(ReadyView, {
|
||||
},
|
||||
},
|
||||
goToBank: {},
|
||||
sendAll: {},
|
||||
goToWallet: {},
|
||||
previous: [],
|
||||
selectCurrency: {},
|
||||
@ -49,6 +50,7 @@ export const SendCash = tests.createExample(ReadyView, {
|
||||
},
|
||||
},
|
||||
goToBank: {},
|
||||
sendAll: {},
|
||||
goToWallet: {},
|
||||
previous: [],
|
||||
selectCurrency: {},
|
||||
|
@ -118,6 +118,16 @@ describe("Destination selection states", () => {
|
||||
expect(state.goToBank.onClick).not.eq(undefined);
|
||||
expect(state.goToWallet.onClick).not.eq(undefined);
|
||||
|
||||
expect(state.amountHandler.value).deep.eq(
|
||||
Amounts.parseOrThrow("ARS:2"),
|
||||
);
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
expect(state.goToBank.onClick).not.eq(undefined);
|
||||
expect(state.goToWallet.onClick).not.eq(undefined);
|
||||
|
||||
expect(state.amountHandler.value).deep.eq(
|
||||
Amounts.parseOrThrow("ARS:2"),
|
||||
);
|
||||
|
@ -17,6 +17,7 @@
|
||||
import { styled } from "@linaria/react";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { AmountField } from "../../components/AmountField.js";
|
||||
import { JustInDevMode } from "../../components/JustInDevMode.js";
|
||||
import { SelectList } from "../../components/SelectList.js";
|
||||
import {
|
||||
Input,
|
||||
@ -283,6 +284,7 @@ export function ReadySendView({
|
||||
goToBank,
|
||||
goToWallet,
|
||||
previous,
|
||||
sendAll,
|
||||
}: State.Ready): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
@ -292,13 +294,18 @@ export function ReadySendView({
|
||||
<i18n.Translate>Specify the amount and the destination</i18n.Translate>
|
||||
</h1>
|
||||
|
||||
<div>
|
||||
<Grid container columns={2} justifyContent="space-between">
|
||||
<AmountField
|
||||
label={i18n.str`Amount`}
|
||||
required
|
||||
handler={amountHandler}
|
||||
/>
|
||||
</div>
|
||||
<JustInDevMode>
|
||||
<Button onClick={sendAll.onClick}>
|
||||
<i18n.Translate>Send all</i18n.Translate>
|
||||
</Button>
|
||||
</JustInDevMode>
|
||||
</Grid>
|
||||
|
||||
<Grid container spacing={1} columns={1}>
|
||||
{previous.length > 0 ? (
|
||||
|
@ -111,8 +111,10 @@ export function HistoryView({
|
||||
balances: Balance[];
|
||||
}): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
const currencies = balances.map((b) => b.available.split(":")[0]);
|
||||
const { pushAlertOnError } = useAlertContext();
|
||||
const currencies = balances
|
||||
.filter((b) => Amounts.isNonZero(b.available))
|
||||
.map((b) => b.available.split(":")[0]);
|
||||
|
||||
const defaultCurrencyIndex = currencies.findIndex(
|
||||
(c) => c === defaultCurrency,
|
||||
|
@ -88,8 +88,8 @@ export interface BackgroundOperations {
|
||||
};
|
||||
setLoggingLevel: {
|
||||
request: {
|
||||
tag?: string,
|
||||
level: LogLevel
|
||||
tag?: string;
|
||||
level: LogLevel;
|
||||
};
|
||||
response: void;
|
||||
};
|
||||
|
@ -186,12 +186,18 @@ const backendHandlers: BackendHandlerType = {
|
||||
setLoggingLevel,
|
||||
};
|
||||
|
||||
async function setLoggingLevel({ tag, level }: { tag?: string, level: LogLevel }): Promise<void> {
|
||||
logger.info(`setting ${tag} to ${level}`)
|
||||
async function setLoggingLevel({
|
||||
tag,
|
||||
level,
|
||||
}: {
|
||||
tag?: string;
|
||||
level: LogLevel;
|
||||
}): Promise<void> {
|
||||
logger.info(`setting ${tag} to ${level}`);
|
||||
if (!tag) {
|
||||
setGlobalLogLevelFromString(level)
|
||||
setGlobalLogLevelFromString(level);
|
||||
} else {
|
||||
setLogLevelFromString(tag, level)
|
||||
setLogLevelFromString(tag, level);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user