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

View File

@ -46,6 +46,8 @@ import {
AbsoluteTime,
TalerProtocolTimestamp,
Duration,
PrepareRefundRequest,
PrepareRefundResult,
} from "@gnu-taler/taler-util";
import {
AbortStatus,
@ -69,6 +71,72 @@ import { guardOperationException } from "./common.js";
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.
*/

View File

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