diff options
author | Florian Dold <florian.dold@gmail.com> | 2020-09-06 18:17:12 +0530 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2020-09-06 18:17:12 +0530 |
commit | c0861f0690425308e3e4126093f4edb2b105e64a (patch) | |
tree | d57074e18977159fb4883a14f92075dc59232b24 | |
parent | cde4d13df8d9af64eccc82dd13965f2045c8f78c (diff) |
handle permanent refund failure
-rw-r--r-- | packages/taler-integrationtests/src/harness.ts | 16 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/operations/refund.ts | 60 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/types/talerTypes.ts | 4 |
3 files changed, 72 insertions, 8 deletions
diff --git a/packages/taler-integrationtests/src/harness.ts b/packages/taler-integrationtests/src/harness.ts index cc5ffa161..d974bdd01 100644 --- a/packages/taler-integrationtests/src/harness.ts +++ b/packages/taler-integrationtests/src/harness.ts @@ -899,10 +899,20 @@ export class ExchangeService implements ExchangeServiceInterface { } async runWirewatchOnce() { - await sh( + await runCommand( + this.globalState, + `exchange-${this.name}-wirewatch-once`, + "taler-exchange-wirewatch", + [...this.timetravelArgArr, "-c", this.configFilename, "-t"], + ); + } + + async runAggregatorOnce() { + await runCommand( this.globalState, - "wirewatch-test", - `taler-exchange-wirewatch ${this.timetravelArg} -c '${this.configFilename}' -t`, + `exchange-${this.name}-aggregator-once`, + "taler-exchange-aggregator", + [...this.timetravelArgArr, "-c", this.configFilename, "-t"], ); } diff --git a/packages/taler-wallet-core/src/operations/refund.ts b/packages/taler-wallet-core/src/operations/refund.ts index 373e17a10..0c89e5241 100644 --- a/packages/taler-wallet-core/src/operations/refund.ts +++ b/packages/taler-wallet-core/src/operations/refund.ts @@ -47,8 +47,6 @@ import { MerchantCoinRefundStatus, MerchantCoinRefundSuccessStatus, MerchantCoinRefundFailureStatus, - codecForMerchantOrderStatusPaid, - AmountString, codecForMerchantOrderRefundPickupResponse, } from "../types/talerTypes"; import { guardOperationException } from "./errors"; @@ -202,6 +200,56 @@ async function storePendingRefund( }; } +async function storeFailedRefund( + tx: TransactionHandle, + p: PurchaseRecord, + r: MerchantCoinRefundFailureStatus, +): Promise<void> { + const refundKey = getRefundKey(r); + + const coin = await tx.get(Stores.coins, r.coin_pub); + if (!coin) { + console.warn("coin not found, can't apply refund"); + return; + } + const denom = await tx.getIndexed( + Stores.denominations.denomPubHashIndex, + coin.denomPubHash, + ); + + if (!denom) { + throw Error("inconsistent database"); + } + + const allDenoms = await tx + .iterIndexed( + Stores.denominations.exchangeBaseUrlIndex, + coin.exchangeBaseUrl, + ) + .toArray(); + + const amountLeft = Amounts.sub( + Amounts.add(coin.currentAmount, Amounts.parseOrThrow(r.refund_amount)) + .amount, + denom.feeRefund, + ).amount; + + const totalRefreshCostBound = getTotalRefreshCost( + allDenoms, + denom, + amountLeft, + ); + + p.refunds[refundKey] = { + type: RefundState.Failed, + obtainedTime: getTimestampNow(), + executionTime: r.execution_time, + refundAmount: Amounts.parseOrThrow(r.refund_amount), + refundFee: denom.feeRefund, + totalRefreshCostBound, + }; +} + async function acceptRefunds( ws: InternalWalletState, proposalId: string, @@ -232,6 +280,10 @@ async function acceptRefunds( const refundKey = getRefundKey(refundStatus); const existingRefundInfo = p.refunds[refundKey]; + const isPermanentFailure = + refundStatus.type === "failure" && + refundStatus.exchange_status === 410; + // Already failed. if (existingRefundInfo?.type === RefundState.Failed) { continue; @@ -244,7 +296,7 @@ async function acceptRefunds( // Still pending. if ( - refundStatus.type === "failure" && + refundStatus.type === "failure" && !isPermanentFailure && existingRefundInfo?.type === RefundState.Pending ) { continue; @@ -254,6 +306,8 @@ async function acceptRefunds( if (refundStatus.type === "success") { await applySuccessfulRefund(tx, p, refreshCoinsMap, refundStatus); + } else if (isPermanentFailure) { + await storeFailedRefund(tx, p, refundStatus); } else { await storePendingRefund(tx, p, refundStatus); } diff --git a/packages/taler-wallet-core/src/types/talerTypes.ts b/packages/taler-wallet-core/src/types/talerTypes.ts index 0b4afda11..c944f1561 100644 --- a/packages/taler-wallet-core/src/types/talerTypes.ts +++ b/packages/taler-wallet-core/src/types/talerTypes.ts @@ -1325,13 +1325,13 @@ export const codecForMerchantCoinRefundFailureStatus = (): Codec< buildCodecForObject<MerchantCoinRefundFailureStatus>() .property("type", codecForConstString("failure")) .property("coin_pub", codecForString()) - .property("exchange_status", codecForConstNumber(200)) + .property("exchange_status", codecForNumber()) .property("rtransaction_id", codecForNumber()) .property("refund_amount", codecForString()) .property("exchange_code", codecOptional(codecForNumber())) .property("exchange_reply", codecOptional(codecForAny())) .property("execution_time", codecForTimestamp) - .build("MerchantCoinRefundSuccessStatus"); + .build("MerchantCoinRefundFailureStatus"); export const codecForMerchantCoinRefundStatus = (): Codec< MerchantCoinRefundStatus |