make withdrawal, pay and refunds work in the WebExtension

This commit is contained in:
Florian Dold 2020-09-09 12:45:49 +05:30
parent 0566406abb
commit 71abddec5e
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
9 changed files with 43 additions and 41 deletions

View File

@ -527,6 +527,16 @@ export async function applyRefund(
amountRefundGone: Amounts.stringify(amountRefundGone), amountRefundGone: Amounts.stringify(amountRefundGone),
amountRefundGranted: Amounts.stringify(amountRefundGranted), amountRefundGranted: Amounts.stringify(amountRefundGranted),
pendingAtExchange, pendingAtExchange,
info: {
contractTermsHash: purchase.contractData.contractTermsHash,
merchant: purchase.contractData.merchant,
orderId: purchase.contractData.orderId,
products: purchase.contractData.products,
summary: purchase.contractData.summary,
fulfillmentMessage: purchase.contractData.fulfillmentMessage,
summary_i18n: purchase.contractData.summaryI18n,
fulfillmentMessage_i18n: purchase.contractData.fulfillmentMessageI18n,
}
}; };
} }

View File

@ -55,6 +55,7 @@ import {
codecForContractTerms, codecForContractTerms,
ContractTerms, ContractTerms,
} from "./talerTypes"; } from "./talerTypes";
import { OrderShortInfo, codecForOrderShortInfo } from "./transactions";
/** /**
* Response for the create reserve request to the wallet. * Response for the create reserve request to the wallet.
@ -880,6 +881,8 @@ export interface ApplyRefundResponse {
amountRefundGone: AmountString; amountRefundGone: AmountString;
pendingAtExchange: boolean; pendingAtExchange: boolean;
info: OrderShortInfo;
} }
export const codecForApplyRefundResponse = (): Codec<ApplyRefundResponse> => export const codecForApplyRefundResponse = (): Codec<ApplyRefundResponse> =>
@ -890,6 +893,7 @@ export const codecForApplyRefundResponse = (): Codec<ApplyRefundResponse> =>
.property("contractTermsHash", codecForString()) .property("contractTermsHash", codecForString())
.property("pendingAtExchange", codecForBoolean()) .property("pendingAtExchange", codecForBoolean())
.property("proposalId", codecForString()) .property("proposalId", codecForString())
.property("info", codecForOrderShortInfo())
.build("ApplyRefundResponse"); .build("ApplyRefundResponse");
export interface SetCoinSuspendedRequest { export interface SetCoinSuspendedRequest {

View File

@ -257,7 +257,8 @@ export function isNonZero(a: AmountJson): boolean {
return a.value > 0 || a.fraction > 0; return a.value > 0 || a.fraction > 0;
} }
export function isZero(a: AmountJson): boolean { export function isZero(a: AmountLike): boolean {
a = jsonifyAmount(a);
return a.value === 0 && a.fraction === 0; return a.value === 0 && a.fraction === 0;
} }

View File

@ -70,7 +70,6 @@ import {
AcceptManualWithdrawalResult, AcceptManualWithdrawalResult,
BalancesResponse, BalancesResponse,
TestPayArgs, TestPayArgs,
PreparePayResultType,
IntegrationTestArgs, IntegrationTestArgs,
codecForAddExchangeRequest, codecForAddExchangeRequest,
codecForGetWithdrawalDetailsForUri, codecForGetWithdrawalDetailsForUri,
@ -80,7 +79,6 @@ import {
codecForApplyRefundRequest, codecForApplyRefundRequest,
codecForAcceptBankIntegratedWithdrawalRequest, codecForAcceptBankIntegratedWithdrawalRequest,
codecForGetExchangeTosRequest, codecForGetExchangeTosRequest,
codecForAbortProposalRequest,
codecForConfirmPayRequest, codecForConfirmPayRequest,
CoreApiResponse, CoreApiResponse,
codecForPreparePayRequest, codecForPreparePayRequest,
@ -95,6 +93,7 @@ import {
codecForPrepareTipRequest, codecForPrepareTipRequest,
codecForAcceptTipRequest, codecForAcceptTipRequest,
codecForAbortPayWithRefundRequest, codecForAbortPayWithRefundRequest,
ApplyRefundResponse,
} from "./types/walletTypes"; } from "./types/walletTypes";
import { Logger } from "./util/logging"; import { Logger } from "./util/logging";
@ -723,7 +722,7 @@ export class Wallet {
*/ */
async applyRefund( async applyRefund(
talerRefundUri: string, talerRefundUri: string,
): Promise<{ contractTermsHash: string; proposalId: string }> { ): Promise<ApplyRefundResponse> {
return applyRefund(this.ws, talerRefundUri); return applyRefund(this.ws, talerRefundUri);
} }

View File

@ -23,22 +23,17 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import * as wxApi from "../wxApi"; import * as wxApi from "../wxApi";
import { AmountView } from "../renderHtml"; import { AmountView } from "../renderHtml";
import { PurchaseDetails } from "taler-wallet-core"; import { PurchaseDetails, ApplyRefundResponse, Amounts } from "taler-wallet-core";
function RefundStatusView(props: { talerRefundUri: string }): JSX.Element { function RefundStatusView(props: { talerRefundUri: string }): JSX.Element {
const [applied, setApplied] = useState(false); const [applyResult, setApplyResult] = useState<ApplyRefundResponse>();
const [purchaseDetails, setPurchaseDetails] = useState<
PurchaseDetails | undefined
>(undefined);
const [errMsg, setErrMsg] = useState<string | undefined>(undefined); const [errMsg, setErrMsg] = useState<string | undefined>(undefined);
useEffect(() => { useEffect(() => {
const doFetch = async (): Promise<void> => { const doFetch = async (): Promise<void> => {
try { try {
const result = await wxApi.applyRefund(props.talerRefundUri); const result = await wxApi.applyRefund(props.talerRefundUri);
setApplied(true); setApplyResult(result);
// const r = await wxApi.getPurchaseDetails(result.proposalId);
// setPurchaseDetails(r);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
setErrMsg(e.message); setErrMsg(e.message);
@ -54,7 +49,7 @@ function RefundStatusView(props: { talerRefundUri: string }): JSX.Element {
return <span>Error: {errMsg}</span>; return <span>Error: {errMsg}</span>;
} }
if (!applied || !purchaseDetails) { if (!applyResult) {
return <span>Updating refund status</span>; return <span>Updating refund status</span>;
} }
@ -62,11 +57,15 @@ function RefundStatusView(props: { talerRefundUri: string }): JSX.Element {
<> <>
<h2>Refund Status</h2> <h2>Refund Status</h2>
<p> <p>
The product <em>{purchaseDetails.contractTerms.summary}</em> has The product <em>{applyResult.info.summary}</em> has
received a total refund of{" "} received a total effective refund of{" "}
<AmountView amount={purchaseDetails.totalRefundAmount} />. <AmountView amount={applyResult.amountRefundGranted} />.
</p> </p>
<p>Note that additional fees from the exchange may apply.</p> {applyResult.pendingAtExchange ? <p>Refund processing is still in progress.</p> : null}
{!Amounts.isZero(applyResult.amountRefundGone) ? <p>
The refund amount of <AmountView amount={applyResult.amountRefundGone} />
could not be applied.
</p> : null}
</> </>
); );
} }

View File

@ -32,6 +32,7 @@ import {
GetWithdrawalDetailsForUriRequest, GetWithdrawalDetailsForUriRequest,
WithdrawUriInfoResponse, WithdrawUriInfoResponse,
TransactionsResponse, TransactionsResponse,
ApplyRefundResponse,
} from "taler-wallet-core"; } from "taler-wallet-core";
export interface ExtendedPermissionsResponse { export interface ExtendedPermissionsResponse {
@ -131,7 +132,7 @@ export function getTransactions(): Promise<TransactionsResponse> {
*/ */
export function applyRefund( export function applyRefund(
talerRefundUri: string, talerRefundUri: string,
): Promise<{ contractTermsHash: string; proposalId: string }> { ): Promise<ApplyRefundResponse> {
return callBackend("applyRefund", { talerRefundUri }); return callBackend("applyRefund", { talerRefundUri });
} }

View File

@ -203,7 +203,7 @@ function makeSyncWalletRedirect(
oldUrl: string, oldUrl: string,
params?: { [name: string]: string | undefined }, params?: { [name: string]: string | undefined },
): Record<string, unknown> { ): Record<string, unknown> {
const innerUrl = new URL(chrome.extension.getURL("/" + url)); const innerUrl = new URL(chrome.extension.getURL(url));
if (params) { if (params) {
for (const key in params) { for (const key in params) {
const p = params[key]; const p = params[key];
@ -296,7 +296,11 @@ function headerListener(
return; return;
} }
console.log("in header listener"); console.log("in header listener");
if (details.statusCode === 402 || details.statusCode === 202) { if (
details.statusCode === 402 ||
details.statusCode === 202 ||
details.statusCode === 200
) {
console.log(`got 402/202 from ${details.url}`); console.log(`got 402/202 from ${details.url}`);
for (const header of details.responseHeaders || []) { for (const header of details.responseHeaders || []) {
if (header.name.toLowerCase() === "taler") { if (header.name.toLowerCase() === "taler") {
@ -332,7 +336,7 @@ function headerListener(
); );
case TalerUriType.TalerRefund: case TalerUriType.TalerRefund:
return makeSyncWalletRedirect( return makeSyncWalletRedirect(
"refund.html", "/static/refund.html",
details.tabId, details.tabId,
details.url, details.url,
{ {

View File

@ -4,10 +4,10 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>Taler Wallet: Refund Status</title> <title>Taler Wallet: Refund Status</title>
<link rel="icon" href="/img/icon.png" /> <link rel="icon" href="/static/img/icon.png" />
<link rel="stylesheet" type="text/css" href="/style/pure.css" /> <link rel="stylesheet" type="text/css" href="/static/style/pure.css" />
<link rel="stylesheet" type="text/css" href="/style/wallet.css" /> <link rel="stylesheet" type="text/css" href="/static/style/wallet.css" />
<script src="/pageEntryPoint.js"></script> <script src="/dist/pageEntryPoint.js"></script>
</head> </head>
<body> <body>

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Taler Wallet: Return Coins to Bank Account</title>
<link rel="icon" href="/img/icon.png" />
<link rel="stylesheet" type="text/css" href="/style/pure.css" />
<link rel="stylesheet" type="text/css" href="/style/wallet.css" />
<script src="/pageEntryPoint.js"></script>
</head>
<body>
<div id="container"></div>
</body>
</html>