aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-09-01 20:37:50 +0530
committerFlorian Dold <florian.dold@gmail.com>2020-09-01 20:37:50 +0530
commit044b7236572089b98a9f230499bb4cd9ad0342a3 (patch)
treef80955c0fdf6e7dc5e836d8b811e43ce637093ab
parent7f4ebca0c4330805ea8f3821dba075b34dd2be58 (diff)
correct refund amounts and better testing
-rw-r--r--packages/taler-integrationtests/src/harness.ts38
-rw-r--r--packages/taler-integrationtests/src/merchantApiTypes.ts4
-rw-r--r--packages/taler-integrationtests/src/test-refund-incremental.ts76
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts17
-rw-r--r--packages/taler-wallet-core/src/util/amounts.ts14
5 files changed, 127 insertions, 22 deletions
diff --git a/packages/taler-integrationtests/src/harness.ts b/packages/taler-integrationtests/src/harness.ts
index 93999c871..0b41923a4 100644
--- a/packages/taler-integrationtests/src/harness.ts
+++ b/packages/taler-integrationtests/src/harness.ts
@@ -42,7 +42,6 @@ import {
CoreApiResponse,
PreparePayResult,
PreparePayRequest,
- codecForPreparePayResultPaymentPossible,
codecForPreparePayResult,
OperationFailedError,
AddExchangeRequest,
@@ -67,6 +66,8 @@ import {
codecForTransactionsResponse,
WithdrawTestBalanceRequest,
AmountString,
+ ApplyRefundRequest,
+ codecForApplyRefundResponse,
} from "taler-wallet-core";
import { URL } from "url";
import axios, { AxiosError } from "axios";
@@ -77,6 +78,7 @@ import {
PostOrderResponse,
MerchantOrderPrivateStatusResponse,
} from "./merchantApiTypes";
+import { ApplyRefundResponse } from "taler-wallet-core";
const exec = util.promisify(require("child_process").exec);
@@ -384,6 +386,32 @@ export class GlobalTestState {
}
}
+ assertAmountLeq(
+ amtExpected: string | AmountJson,
+ amtActual: string | AmountJson,
+ ): void {
+ let ja1: AmountJson;
+ let ja2: AmountJson;
+ if (typeof amtExpected === "string") {
+ ja1 = Amounts.parseOrThrow(amtExpected);
+ } else {
+ ja1 = amtExpected;
+ }
+ if (typeof amtActual === "string") {
+ ja2 = Amounts.parseOrThrow(amtActual);
+ } else {
+ ja2 = amtActual;
+ }
+
+ if (Amounts.cmp(ja1, ja2) > 0) {
+ throw Error(
+ `test assertion failed: expected ${Amounts.stringify(
+ ja1,
+ )} to be less or equal (leq) than ${Amounts.stringify(ja2)}`,
+ );
+ }
+ }
+
private shutdownSync(): void {
for (const s of this.servers) {
s.close();
@@ -1512,6 +1540,14 @@ export class WalletCli {
);
}
+ async applyRefund(req: ApplyRefundRequest): Promise<ApplyRefundResponse> {
+ const resp = await this.apiRequest("applyRefund", req);
+ if (resp.type === "response") {
+ return codecForApplyRefundResponse().decode(resp.result);
+ }
+ throw new OperationFailedError(resp.error);
+ }
+
async preparePay(req: PreparePayRequest): Promise<PreparePayResult> {
const resp = await this.apiRequest("preparePay", req);
if (resp.type === "response") {
diff --git a/packages/taler-integrationtests/src/merchantApiTypes.ts b/packages/taler-integrationtests/src/merchantApiTypes.ts
index d08c354a1..550c5e90c 100644
--- a/packages/taler-integrationtests/src/merchantApiTypes.ts
+++ b/packages/taler-integrationtests/src/merchantApiTypes.ts
@@ -83,8 +83,8 @@ export const codecForCheckPaymentPaidResponse = (): Codec<
> =>
buildCodecForObject<CheckPaymentPaidResponse>()
.property("order_status", codecForConstString("paid"))
- .property("refunded", codecForBoolean)
- .property("wired", codecForBoolean)
+ .property("refunded", codecForBoolean())
+ .property("wired", codecForBoolean())
.property("deposit_total", codecForAmountString())
.property("exchange_ec", codecForNumber())
.property("exchange_hc", codecForNumber())
diff --git a/packages/taler-integrationtests/src/test-refund-incremental.ts b/packages/taler-integrationtests/src/test-refund-incremental.ts
index e823b40a1..3439f7047 100644
--- a/packages/taler-integrationtests/src/test-refund-incremental.ts
+++ b/packages/taler-integrationtests/src/test-refund-incremental.ts
@@ -24,6 +24,7 @@ import {
MerchantPrivateApi,
} from "./harness";
import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
+import { TransactionType, Amounts } from "taler-wallet-core";
/**
* Run test for basic, bank-integrated withdrawal.
@@ -47,7 +48,7 @@ runTest(async (t: GlobalTestState) => {
const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
order: {
summary: "Buy me!",
- amount: "TESTKUDOS:5",
+ amount: "TESTKUDOS:10",
fulfillment_url: "taler://fulfillment-success/thx",
},
});
@@ -88,9 +89,21 @@ runTest(async (t: GlobalTestState) => {
console.log("first refund increase response", ref);
+ {
+ let wr = await wallet.applyRefund({
+ talerRefundUri: ref.talerRefundUri,
+ });
+ console.log(wr);
+ const txs = await wallet.getTransactions();
+ console.log(
+ "transactions after applying first refund:",
+ JSON.stringify(txs, undefined, 2),
+ );
+ }
+
// Wait at least a second, because otherwise the increased
// refund will be grouped with the previous one.
- await delayMs(1.2);
+ await delayMs(1200);
ref = await MerchantPrivateApi.giveRefund(merchant, {
amount: "TESTKUDOS:5",
@@ -101,10 +114,25 @@ runTest(async (t: GlobalTestState) => {
console.log("second refund increase response", ref);
- let r = await wallet.apiRequest("applyRefund", {
- talerRefundUri: ref.talerRefundUri,
+ // Wait at least a second, because otherwise the increased
+ // refund will be grouped with the previous one.
+ await delayMs(1200);
+
+ ref = await MerchantPrivateApi.giveRefund(merchant, {
+ amount: "TESTKUDOS:10",
+ instance: "default",
+ justification: "bar",
+ orderId: orderResp.order_id,
});
- console.log(r);
+
+ console.log("third refund increase response", ref);
+
+ {
+ let wr = await wallet.applyRefund({
+ talerRefundUri: ref.talerRefundUri,
+ });
+ console.log(wr);
+ }
orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
orderId: orderResp.order_id,
@@ -112,17 +140,43 @@ runTest(async (t: GlobalTestState) => {
t.assertTrue(orderStatus.order_status === "paid");
- t.assertAmountEquals(orderStatus.refund_amount, "TESTKUDOS:5");
+ t.assertAmountEquals(orderStatus.refund_amount, "TESTKUDOS:10");
console.log(JSON.stringify(orderStatus, undefined, 2));
await wallet.runUntilDone();
- r = await wallet.apiRequest("getBalances", {});
- console.log(JSON.stringify(r, undefined, 2));
-
- r = await wallet.apiRequest("getTransactions", {});
- console.log(JSON.stringify(r, undefined, 2));
+ const bal = await wallet.getBalances();
+ console.log(JSON.stringify(bal, undefined, 2));
+
+ {
+ const txs = await wallet.getTransactions();
+ console.log(JSON.stringify(txs, undefined, 2));
+
+ const txTypes = txs.transactions.map((x) => x.type);
+ t.assertDeepEqual(txTypes, [
+ "withdrawal",
+ "payment",
+ "refund",
+ "refund",
+ "refund",
+ ]);
+
+ for (const tx of txs.transactions) {
+ if (tx.type !== TransactionType.Refund) {
+ continue;
+ }
+ t.assertAmountLeq(tx.amountEffective, tx.amountRaw);
+ }
+
+ const raw = Amounts.sum(
+ txs.transactions
+ .filter((x) => x.type === TransactionType.Refund)
+ .map((x) => x.amountRaw),
+ ).amount;
+
+ t.assertAmountEquals(raw, "TESTKUDOS:10");
+ }
await t.shutdown();
});
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 2515415d2..da75f6e53 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -281,22 +281,27 @@ export async function getTransactions(
groupKey,
);
let r0: WalletRefundItem | undefined;
- let amountEffective = Amounts.getZero(
+ let amountRaw = Amounts.getZero(
pr.contractData.amount.currency,
);
- let amountRaw = Amounts.getZero(pr.contractData.amount.currency);
+ let amountEffective = Amounts.getZero(pr.contractData.amount.currency);
for (const rk of Object.keys(pr.refunds)) {
const refund = pr.refunds[rk];
+ const myGroupKey = `${refund.executionTime.t_ms}`;
+ if (myGroupKey !== groupKey) {
+ continue;
+ }
if (!r0) {
r0 = refund;
}
+
if (refund.type === RefundState.Applied) {
- amountEffective = Amounts.add(
- amountEffective,
- refund.refundAmount,
- ).amount;
amountRaw = Amounts.add(
amountRaw,
+ refund.refundAmount,
+ ).amount;
+ amountEffective = Amounts.add(
+ amountEffective,
Amounts.sub(
refund.refundAmount,
refund.refundFee,
diff --git a/packages/taler-wallet-core/src/util/amounts.ts b/packages/taler-wallet-core/src/util/amounts.ts
index 2a8c47905..2f912cff4 100644
--- a/packages/taler-wallet-core/src/util/amounts.ts
+++ b/packages/taler-wallet-core/src/util/amounts.ts
@@ -101,11 +101,21 @@ export function getZero(currency: string): AmountJson {
};
}
-export function sum(amounts: AmountJson[]): Result {
+export type AmountLike = AmountString | AmountJson;
+
+export function jsonifyAmount(amt: AmountLike): AmountJson {
+ if (typeof amt === "string") {
+ return parseOrThrow(amt);
+ }
+ return amt;
+}
+
+export function sum(amounts: AmountLike[]): Result {
if (amounts.length <= 0) {
throw Error("can't sum zero amounts");
}
- return add(amounts[0], ...amounts.slice(1));
+ const jsonAmounts = amounts.map((x) => jsonifyAmount(x));
+ return add(jsonAmounts[0], ...jsonAmounts.slice(1));
}
/**