add prepareRefund operation to gather information about the refund before confirm

This commit is contained in:
Sebastian 2022-05-02 19:21:13 -03:00
parent 9996c27488
commit e5c9f588e4
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
3 changed files with 129 additions and 42 deletions

View File

@ -276,6 +276,18 @@ export class ReturnCoinsRequest {
static checked: (obj: any) => ReturnCoinsRequest; static checked: (obj: any) => ReturnCoinsRequest;
} }
export interface PrepareRefundResult {
proposalId: string;
applied: number;
failed: number;
total: number;
amountEffectivePaid: AmountString;
info: OrderShortInfo;
}
export interface PrepareTipResult { export interface PrepareTipResult {
/** /**
* Unique ID for the tip assigned by the wallet. * Unique ID for the tip assigned by the wallet.
@ -1003,6 +1015,17 @@ export const codecForForceRefreshRequest = (): Codec<ForceRefreshRequest> =>
.property("coinPubList", codecForList(codecForString())) .property("coinPubList", codecForList(codecForString()))
.build("ForceRefreshRequest"); .build("ForceRefreshRequest");
export interface PrepareRefundRequest {
talerRefundUri: string;
}
export const codecForPrepareRefundRequest = (): Codec<PrepareRefundRequest> =>
buildCodecForObject<PrepareRefundRequest>()
.property("talerRefundUri", codecForString())
.build("PrepareRefundRequest");
export interface PrepareTipRequest { export interface PrepareTipRequest {
talerTipUri: string; talerTipUri: string;
} }

View File

@ -46,6 +46,8 @@ import {
AbsoluteTime, AbsoluteTime,
TalerProtocolTimestamp, TalerProtocolTimestamp,
Duration, Duration,
PrepareRefundRequest,
PrepareRefundResult,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { import {
AbortStatus, AbortStatus,
@ -69,6 +71,72 @@ import { guardOperationException } from "./common.js";
const logger = new Logger("refund.ts"); const logger = new Logger("refund.ts");
export async function prepareRefund(
ws: InternalWalletState,
talerRefundUri: string,
): Promise<PrepareRefundResult> {
const parseResult = parseRefundUri(talerRefundUri);
logger.trace("preparing refund offer", parseResult);
if (!parseResult) {
throw Error("invalid refund URI");
}
const purchase = await ws.db
.mktx((x) => ({
purchases: x.purchases,
}))
.runReadOnly(async (tx) => {
return tx.purchases.indexes.byMerchantUrlAndOrderId.get([
parseResult.merchantBaseUrl,
parseResult.orderId,
]);
});
if (!purchase) {
throw Error(
`no purchase for the taler://refund/ URI (${talerRefundUri}) was found`,
);
}
const proposalId = purchase.proposalId;
const rfs = Object.values(purchase.refunds)
let applied = 0;
let failed = 0;
const total = rfs.length;
rfs.forEach((refund) => {
if (refund.type === RefundState.Failed) {
failed = failed + 1;
}
if (refund.type === RefundState.Applied) {
applied = applied + 1;
}
});
const { contractData: c } = purchase.download
return {
proposalId,
amountEffectivePaid: Amounts.stringify(purchase.totalPayCost),
applied,
failed,
total,
info: {
contractTermsHash: c.contractTermsHash,
merchant: c.merchant,
orderId: c.orderId,
products: c.products,
summary: c.summary,
fulfillmentMessage: c.fulfillmentMessage,
summary_i18n: c.summaryI18n,
fulfillmentMessage_i18n:
c.fulfillmentMessageI18n,
},
}
}
/** /**
* Retry querying and applying refunds for an order later. * Retry querying and applying refunds for an order later.
*/ */

View File

@ -23,9 +23,7 @@
* Imports. * Imports.
*/ */
import { import {
AcceptManualWithdrawalResult, AbsoluteTime, AcceptManualWithdrawalResult, AmountJson,
AcceptWithdrawalResponse,
AmountJson,
Amounts, Amounts,
BalancesResponse, BalancesResponse,
codecForAbortPayWithRefundRequest, codecForAbortPayWithRefundRequest,
@ -48,8 +46,7 @@ import {
codecForImportDbRequest, codecForImportDbRequest,
codecForIntegrationTestArgs, codecForIntegrationTestArgs,
codecForListKnownBankAccounts, codecForListKnownBankAccounts,
codecForPreparePayRequest, codecForPreparePayRequest, codecForPrepareRefundRequest, codecForPrepareTipRequest,
codecForPrepareTipRequest,
codecForRetryTransactionRequest, codecForRetryTransactionRequest,
codecForSetCoinSuspendedRequest, codecForSetCoinSuspendedRequest,
codecForSetWalletDeviceIdRequest, codecForSetWalletDeviceIdRequest,
@ -59,8 +56,7 @@ import {
codecForWithdrawFakebankRequest, codecForWithdrawFakebankRequest,
codecForWithdrawTestBalance, codecForWithdrawTestBalance,
CoinDumpJson, CoinDumpJson,
CoreApiResponse, CoreApiResponse, Duration, durationFromSpec,
durationFromSpec,
durationMin, durationMin,
ExchangeListItem, ExchangeListItem,
ExchangesListRespose, ExchangesListRespose,
@ -73,14 +69,23 @@ import {
parsePaytoUri, parsePaytoUri,
PaytoUri, PaytoUri,
RefreshReason, RefreshReason,
TalerErrorCode, TalerErrorCode, URL,
AbsoluteTime, WalletNotification
URL,
WalletNotification,
Duration,
CancellationToken,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { timeStamp } from "console"; import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
import {
CryptoDispatcher,
CryptoWorkerFactory
} from "./crypto/workers/cryptoDispatcher.js";
import {
AuditorTrustRecord,
CoinSourceType,
exportDb,
importDb,
ReserveRecordStatus,
WalletStoresV1
} from "./db.js";
import { getErrorDetailFromException, TalerError } from "./errors.js";
import { import {
DenomInfo, DenomInfo,
ExchangeOperations, ExchangeOperations,
@ -89,21 +94,8 @@ import {
MerchantOperations, MerchantOperations,
NotificationListener, NotificationListener,
RecoupOperations, RecoupOperations,
ReserveOperations, ReserveOperations
} from "./internal-wallet-state.js"; } from "./internal-wallet-state.js";
import {
CryptoDispatcher,
CryptoWorkerFactory,
} from "./crypto/workers/cryptoDispatcher.js";
import {
AuditorTrustRecord,
CoinSourceType,
exportDb,
importDb,
ReserveRecordStatus,
WalletStoresV1,
} from "./db.js";
import { getErrorDetailFromException, TalerError } from "./errors.js";
import { exportBackup } from "./operations/backup/export.js"; import { exportBackup } from "./operations/backup/export.js";
import { import {
addBackupProvider, addBackupProvider,
@ -115,7 +107,7 @@ import {
loadBackupRecovery, loadBackupRecovery,
processBackupForProvider, processBackupForProvider,
removeBackupProvider, removeBackupProvider,
runBackupCycle, runBackupCycle
} from "./operations/backup/index.js"; } from "./operations/backup/index.js";
import { setWalletDeviceId } from "./operations/backup/state.js"; import { setWalletDeviceId } from "./operations/backup/state.js";
import { getBalances } from "./operations/balance.js"; import { getBalances } from "./operations/balance.js";
@ -123,7 +115,7 @@ import {
createDepositGroup, createDepositGroup,
getFeeForDeposit, getFeeForDeposit,
processDepositGroup, processDepositGroup,
trackDepositGroup, trackDepositGroup
} from "./operations/deposits.js"; } from "./operations/deposits.js";
import { import {
acceptExchangeTermsOfService, acceptExchangeTermsOfService,
@ -132,69 +124,69 @@ import {
getExchangeRequestTimeout, getExchangeRequestTimeout,
getExchangeTrust, getExchangeTrust,
updateExchangeFromUrl, updateExchangeFromUrl,
updateExchangeTermsOfService, updateExchangeTermsOfService
} from "./operations/exchanges.js"; } from "./operations/exchanges.js";
import { getMerchantInfo } from "./operations/merchants.js"; import { getMerchantInfo } from "./operations/merchants.js";
import { import {
confirmPay, confirmPay,
preparePayForUri, preparePayForUri,
processDownloadProposal, processDownloadProposal,
processPurchasePay, processPurchasePay
} from "./operations/pay.js"; } from "./operations/pay.js";
import { getPendingOperations } from "./operations/pending.js"; import { getPendingOperations } from "./operations/pending.js";
import { createRecoupGroup, processRecoupGroup } from "./operations/recoup.js"; import { createRecoupGroup, processRecoupGroup } from "./operations/recoup.js";
import { import {
autoRefresh, autoRefresh,
createRefreshGroup, createRefreshGroup,
processRefreshGroup, processRefreshGroup
} from "./operations/refresh.js"; } from "./operations/refresh.js";
import { import {
abortFailedPayWithRefund, abortFailedPayWithRefund,
applyRefund, applyRefund,
processPurchaseQueryRefund, prepareRefund,
processPurchaseQueryRefund
} from "./operations/refund.js"; } from "./operations/refund.js";
import { import {
createReserve, createReserve,
createTalerWithdrawReserve, createTalerWithdrawReserve,
getFundingPaytoUris, getFundingPaytoUris,
processReserve, processReserve
} from "./operations/reserves.js"; } from "./operations/reserves.js";
import { import {
runIntegrationTest, runIntegrationTest,
testPay, testPay,
withdrawTestBalance, withdrawTestBalance
} from "./operations/testing.js"; } from "./operations/testing.js";
import { acceptTip, prepareTip, processTip } from "./operations/tip.js"; import { acceptTip, prepareTip, processTip } from "./operations/tip.js";
import { import {
deleteTransaction, deleteTransaction,
getTransactions, getTransactions,
retryTransaction, retryTransaction
} from "./operations/transactions.js"; } from "./operations/transactions.js";
import { import {
getExchangeWithdrawalInfo, getExchangeWithdrawalInfo,
getWithdrawalDetailsForUri, getWithdrawalDetailsForUri,
processWithdrawGroup, processWithdrawGroup
} from "./operations/withdraw.js"; } from "./operations/withdraw.js";
import { import {
PendingOperationsResponse, PendingOperationsResponse,
PendingTaskInfo, PendingTaskInfo,
PendingTaskType, PendingTaskType
} from "./pending-types.js"; } from "./pending-types.js";
import { assertUnreachable } from "./util/assertUnreachable.js"; import { assertUnreachable } from "./util/assertUnreachable.js";
import { AsyncOpMemoMap, AsyncOpMemoSingle } from "./util/asyncMemo.js"; import { AsyncOpMemoMap, AsyncOpMemoSingle } from "./util/asyncMemo.js";
import { import {
HttpRequestLibrary, HttpRequestLibrary,
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow
} from "./util/http.js"; } from "./util/http.js";
import { import {
AsyncCondition, AsyncCondition,
OpenedPromise, OpenedPromise,
openPromise, openPromise
} from "./util/promiseUtils.js"; } from "./util/promiseUtils.js";
import { DbAccess, GetReadWriteAccess } from "./util/query.js"; import { DbAccess, GetReadWriteAccess } from "./util/query.js";
import { TimerAPI, TimerGroup } from "./util/timer.js"; import { TimerAPI, TimerGroup } from "./util/timer.js";
import { WalletCoreApiClient } from "./wallet-api-types.js"; import { WalletCoreApiClient } from "./wallet-api-types.js";
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
const builtinAuditors: AuditorTrustRecord[] = [ const builtinAuditors: AuditorTrustRecord[] = [
{ {
@ -908,6 +900,10 @@ async function dispatchRequestInternal(
const req = codecForPrepareTipRequest().decode(payload); const req = codecForPrepareTipRequest().decode(payload);
return await prepareTip(ws, req.talerTipUri); return await prepareTip(ws, req.talerTipUri);
} }
case "prepareRefund": {
const req = codecForPrepareRefundRequest().decode(payload);
return await prepareRefund(ws, req.talerRefundUri);
}
case "acceptTip": { case "acceptTip": {
const req = codecForAcceptTipRequest().decode(payload); const req = codecForAcceptTipRequest().decode(payload);
await acceptTip(ws, req.walletTipId); await acceptTip(ws, req.walletTipId);