aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-util/src/wallet-types.ts11
-rw-r--r--packages/taler-wallet-core/src/pay-merchant.ts64
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts3
-rw-r--r--packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts1
-rw-r--r--packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts143
-rw-r--r--packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx1
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Application.tsx2
7 files changed, 127 insertions, 98 deletions
diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts
index 77c531f39..dd8eb29a2 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -48,6 +48,7 @@ import {
} from "./codec.js";
import {
CurrencySpecification,
+ TalerMerchantApi,
TemplateParams,
WithdrawalOperationStatus,
canonicalizeBaseUrl,
@@ -1851,9 +1852,9 @@ export interface PrepareBankIntegratedWithdrawalRequest {
export const codecForPrepareBankIntegratedWithdrawalRequest =
(): Codec<PrepareBankIntegratedWithdrawalRequest> =>
buildCodecForObject<PrepareBankIntegratedWithdrawalRequest>()
- .property("talerWithdrawUri", codecForString())
- .property("selectedExchange", codecOptional(codecForString()))
- .build("PrepareBankIntegratedWithdrawalRequest");
+ .property("talerWithdrawUri", codecForString())
+ .property("selectedExchange", codecOptional(codecForString()))
+ .build("PrepareBankIntegratedWithdrawalRequest");
export interface PrepareBankIntegratedWithdrawalResponse {
transactionId?: string;
@@ -2043,6 +2044,10 @@ export interface CheckPayTemplateRequest {
talerPayTemplateUri: string;
}
+export type CheckPayTemplateReponse = TalerMerchantApi.WalletTemplateDetails & {
+ supportedCurrencies: string[];
+}
+
export const codecForCheckPayTemplateRequest =
(): Codec<CheckPayTemplateRequest> =>
buildCodecForObject<CheckPayTemplateRequest>()
diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts
index f08db3a6a..8b6cb5e8d 100644
--- a/packages/taler-wallet-core/src/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/pay-merchant.ts
@@ -34,6 +34,8 @@ import {
assertUnreachable,
AsyncFlag,
checkDbInvariant,
+ CheckPaymentResponse,
+ CheckPayTemplateReponse,
CheckPayTemplateRequest,
codecForAbortResponse,
codecForMerchantContractTerms,
@@ -79,6 +81,7 @@ import {
TalerErrorCode,
TalerErrorDetail,
TalerMerchantApi,
+ TalerMerchantInstanceHttpClient,
TalerPreciseTimestamp,
TalerProtocolViolationError,
TalerUriAction,
@@ -627,8 +630,7 @@ async function processDownloadProposal(
if (proposal.purchaseStatus != PurchaseStatus.PendingDownloadingProposal) {
logger.error(
- `unexpected state ${proposal.purchaseStatus}/${
- PurchaseStatus[proposal.purchaseStatus]
+ `unexpected state ${proposal.purchaseStatus}/${PurchaseStatus[proposal.purchaseStatus]
} for ${ctx.transactionId} in processDownloadProposal`,
);
return TaskRunResult.finished();
@@ -887,8 +889,7 @@ async function createOrReusePurchase(
oldProposal.claimToken === claimToken
) {
logger.info(
- `Found old proposal (status=${
- PurchaseStatus[oldProposal.purchaseStatus]
+ `Found old proposal (status=${PurchaseStatus[oldProposal.purchaseStatus]
}) for order ${orderId} at ${merchantBaseUrl}`,
);
if (oldProposal.purchaseStatus === PurchaseStatus.DialogShared) {
@@ -1601,16 +1602,31 @@ async function downloadTemplate(
export async function checkPayForTemplate(
wex: WalletExecutionContext,
req: CheckPayTemplateRequest,
-): Promise<TalerMerchantApi.WalletTemplateDetails> {
+): Promise<CheckPayTemplateReponse> {
const parsedUri = parsePayTemplateUri(req.talerPayTemplateUri);
if (!parsedUri) {
throw Error("invalid taler-template URI");
}
- return await downloadTemplate(
+ const asd = await downloadTemplate(
wex,
parsedUri.merchantBaseUrl,
parsedUri.templateId,
);
+
+ const merchantApi = new TalerMerchantInstanceHttpClient(
+ parsedUri.merchantBaseUrl,
+ wex.http,
+ );
+
+ const cfg = await merchantApi.getConfig()
+ if (cfg.type === "fail") {
+ throw TalerError.fromUncheckedDetail(cfg.detail);
+ }
+
+ return {
+ ...asd,
+ supportedCurrencies: Object.keys(cfg.body.currencies)
+ }
}
export async function preparePayForTemplate(
@@ -1630,28 +1646,26 @@ export async function preparePayForTemplate(
parsedUri.templateId,
);
- const amountFromUri = templateInfo.editable_defaults?.amount;
- if (amountFromUri != null) {
- const templateParamsAmount = req.templateParams?.amount;
- if (templateParamsAmount != null) {
- templateDetails.amount = templateParamsAmount as AmountString;
- } else {
- if (Amounts.isCurrency(amountFromUri)) {
- throw Error(
- "Amount from template URI only has a currency without value. The value must be provided in the templateParams.",
- );
- } else {
- templateDetails.amount = amountFromUri as AmountString;
- }
+ const templateParamsAmount = req.templateParams?.amount as AmountString | undefined;
+ if (templateParamsAmount === null) {
+ const amountFromUri = templateInfo.editable_defaults?.amount;
+ if (amountFromUri != null) {
+ templateDetails.amount = amountFromUri as AmountString;
}
+ } else {
+ templateDetails.amount = templateParamsAmount
}
- if (
- templateInfo.editable_defaults?.summary !== undefined &&
- typeof templateInfo.editable_defaults?.summary === "string"
- ) {
- templateDetails.summary =
- req.templateParams?.summary ?? templateInfo.editable_defaults?.summary;
+
+ const templateParamsSummary = req.templateParams?.summary;
+ if (templateParamsSummary === null) {
+ const summaryFromUri = templateInfo.editable_defaults?.summary;
+ if (summaryFromUri != null) {
+ templateDetails.summary = summaryFromUri;
+ }
+ } else {
+ templateDetails.summary = templateParamsSummary
}
+
const reqUrl = new URL(
`templates/${parsedUri.templateId}`,
parsedUri.merchantBaseUrl,
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
index 2a1b7d170..1bcab801c 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -40,6 +40,7 @@ import {
BalancesResponse,
CanonicalizeBaseUrlRequest,
CanonicalizeBaseUrlResponse,
+ CheckPayTemplateReponse,
CheckPayTemplateRequest,
CheckPeerPullCreditRequest,
CheckPeerPullCreditResponse,
@@ -553,7 +554,7 @@ export type SharePaymentOp = {
export type CheckPayForTemplateOp = {
op: WalletApiOperation.CheckPayForTemplate;
request: CheckPayTemplateRequest;
- response: TalerMerchantApi.WalletTemplateDetails;
+ response: CheckPayTemplateReponse;
};
/**
diff --git a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts
index f5a8c8814..80d952217 100644
--- a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts
@@ -53,7 +53,6 @@ export namespace State {
export interface FillTemplate {
status: "fill-template";
error: undefined;
- currency: string;
amount?: AmountFieldHandler;
summary?: TextFieldHandler;
onCreate: ButtonHandler;
diff --git a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts
index 6b4584fea..4881f6e91 100644
--- a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts
@@ -14,7 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { Amounts, PreparePayResult } from "@gnu-taler/taler-util";
+import { AmountJson, Amounts, PreparePayResult } from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js";
@@ -23,49 +23,39 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { AmountFieldHandler, TextFieldHandler } from "../../mui/handlers.js";
import { Props, State } from "./index.js";
+import { RecursiveState } from "../../utils/index.js";
export function useComponentState({
talerTemplateUri,
cancel,
goToWalletManualWithdraw,
onSuccess,
-}: Props): State {
+}: Props): RecursiveState<State> {
const api = useBackendContext();
const { i18n } = useTranslationContext();
const { safely } = useAlertContext();
- const url = talerTemplateUri ? new URL(talerTemplateUri) : undefined;
+ // const url = talerTemplateUri ? new URL(talerTemplateUri) : undefined;
+ // const parsedAmount = !amountParam ? undefined : Amounts.parse(amountParam);
+ // const currency = parsedAmount ? parsedAmount.currency : amountParam;
- const amountParam = !url
- ? undefined
- : url.searchParams.get("amount") ?? undefined;
- const summaryParam = !url
- ? undefined
- : url.searchParams.get("summary") ?? undefined;
+ // const initialAmount =
+ // parsedAmount ?? (currency ? Amounts.zeroOfCurrency(currency) : undefined);
- const parsedAmount = !amountParam ? undefined : Amounts.parse(amountParam);
- const currency = parsedAmount ? parsedAmount.currency : amountParam;
-
- const initialAmount =
- parsedAmount ?? (currency ? Amounts.zeroOfCurrency(currency) : undefined);
- const [amount, setAmount] = useState(initialAmount);
- const [summary, setSummary] = useState(summaryParam);
const [newOrder, setNewOrder] = useState("");
const hook = useAsyncAsHook(async () => {
if (!talerTemplateUri) throw Error("ERROR_NO-URI-FOR-PAYMENT-TEMPLATE");
+ const templateP = await api.wallet.call(
+ WalletApiOperation.CheckPayForTemplate, { talerPayTemplateUri: talerTemplateUri },
+ );
+ const requireMoreInfo = !templateP.template_contract.amount || !templateP.template_contract.summary;
let payStatus: PreparePayResult | undefined = undefined;
- if (!amountParam && !summaryParam) {
- payStatus = await api.wallet.call(
- WalletApiOperation.PreparePayForTemplate,
- {
- talerPayTemplateUri: talerTemplateUri,
- templateParams: {},
- },
- );
+ if (!requireMoreInfo) {
+ payStatus = await api.wallet.call(WalletApiOperation.PreparePayForTemplate, { talerPayTemplateUri: talerTemplateUri });
}
const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
- return { payStatus, balance, uri: talerTemplateUri };
+ return { payStatus, balance, uri: talerTemplateUri, templateP };
}, []);
if (!hook) {
@@ -108,61 +98,82 @@ export function useComponentState({
};
}
- async function createOrder() {
- try {
- const templateParams: Record<string, string> = {};
- if (amount) {
- templateParams["amount"] = Amounts.stringify(amount);
- }
- if (summary) {
- templateParams["summary"] = summary;
+ return () => {
+ const cfg = hook.response.templateP.template_contract;
+ const def = hook.response.templateP.editable_defaults;
+
+ const fixedAmount = cfg.amount !== undefined ? Amounts.parseOrThrow(cfg.amount) : undefined;
+ const fixedSummary = cfg.summary !== undefined ? cfg.summary : undefined;
+
+ const defaultAmount = def?.amount !== undefined ? Amounts.parseOrThrow(def.amount) : undefined;
+ const defaultSummary = def?.summary !== undefined ? def.summary : undefined;
+
+ const zero = fixedAmount ? Amounts.zeroOfAmount(fixedAmount) :
+ cfg.currency !== undefined ? Amounts.zeroOfCurrency(cfg.currency) :
+ defaultAmount !== undefined ? Amounts.zeroOfAmount(defaultAmount) :
+ def?.currency !== undefined ? Amounts.zeroOfCurrency(def.currency) :
+ Amounts.zeroOfCurrency(hook.response.templateP.supportedCurrencies[0]);
+
+ const [amount, setAmount] = useState(defaultAmount ?? zero);
+ const [summary, setSummary] = useState(defaultSummary ?? "");
+
+ async function createOrder() {
+ try {
+ const templateParams: Record<string, string> = {};
+ if (amount && !fixedAmount) {
+ templateParams["amount"] = Amounts.stringify(amount);
+ }
+ if (summary && !fixedSummary) {
+ templateParams["summary"] = summary;
+ }
+ const payStatus = await api.wallet.call(
+ WalletApiOperation.PreparePayForTemplate,
+ {
+ talerPayTemplateUri: talerTemplateUri,
+ templateParams,
+ },
+ );
+ setNewOrder(payStatus.talerUri!);
+ } catch (e) {
+ console.error(e);
}
- const payStatus = await api.wallet.call(
- WalletApiOperation.PreparePayForTemplate,
- {
- talerPayTemplateUri: talerTemplateUri,
- templateParams,
- },
- );
- setNewOrder(payStatus.talerUri!);
- } catch (e) {
- console.error(e);
}
- }
- const errors = undefinedIfEmpty({
- amount: amount && Amounts.isZero(amount) ? i18n.str`required` : undefined,
- summary: summary !== undefined && !summary ? i18n.str`required` : undefined,
- });
- return {
- status: "fill-template",
- error: undefined,
- currency: currency!, //currency is always not null
- amount:
- amount !== undefined
- ? ({
+
+ const errors = undefinedIfEmpty({
+ amount: fixedAmount !== undefined ? undefined : amount && Amounts.isZero(amount) ? i18n.str`required` : undefined,
+ summary: fixedSummary !== undefined ? undefined : summary !== undefined && !summary ? i18n.str`required` : undefined,
+ });
+ return {
+ status: "fill-template",
+ error: undefined,
+ amount:
+ fixedAmount === undefined
+ ? ({
onInput: (a) => {
setAmount(a);
},
value: amount,
error: errors?.amount,
} as AmountFieldHandler)
- : undefined,
- summary:
- summary !== undefined
- ? ({
+ : undefined,
+ summary:
+ fixedSummary === undefined
+ ? ({
onInput: (t) => {
setSummary(t);
},
value: summary,
error: errors?.summary,
} as TextFieldHandler)
- : undefined,
- onCreate: {
- onClick: errors
- ? undefined
- : safely("create order for pay template", createOrder),
- },
- };
+ : undefined,
+ onCreate: {
+ onClick: errors
+ ? undefined
+ : safely("create order for pay template", createOrder),
+ },
+ };
+ }
+
}
function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
diff --git a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx
index 88658b5e1..7efbb32e9 100644
--- a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx
@@ -23,7 +23,6 @@ import { TextField } from "../../mui/TextField.js";
import { State } from "./index.js";
export function ReadyView({
- currency,
amount,
summary,
onCreate,
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx
index 884c2eab7..893122c0f 100644
--- a/packages/taler-wallet-webextension/src/wallet/Application.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx
@@ -157,7 +157,7 @@ export function Application(): VNode {
)}
/>
-<Route
+ <Route
path={Pages.balanceHistory.pattern}
component={({ currency }: { currency?: string }) => (
<WalletTemplate path="balance" goToTransaction={redirectToTxInfo} goToURL={redirectToURL}>