summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-09-06 18:17:12 +0530
committerFlorian Dold <florian.dold@gmail.com>2020-09-06 18:17:12 +0530
commitc0861f0690425308e3e4126093f4edb2b105e64a (patch)
treed57074e18977159fb4883a14f92075dc59232b24
parentcde4d13df8d9af64eccc82dd13965f2045c8f78c (diff)
downloadwallet-core-c0861f0690425308e3e4126093f4edb2b105e64a.tar.gz
wallet-core-c0861f0690425308e3e4126093f4edb2b105e64a.tar.bz2
wallet-core-c0861f0690425308e3e4126093f4edb2b105e64a.zip
handle permanent refund failure
-rw-r--r--packages/taler-integrationtests/src/harness.ts16
-rw-r--r--packages/taler-wallet-core/src/operations/refund.ts60
-rw-r--r--packages/taler-wallet-core/src/types/talerTypes.ts4
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