correct refund amounts and better testing
This commit is contained in:
parent
7f4ebca0c4
commit
044b723657
@ -42,7 +42,6 @@ import {
|
|||||||
CoreApiResponse,
|
CoreApiResponse,
|
||||||
PreparePayResult,
|
PreparePayResult,
|
||||||
PreparePayRequest,
|
PreparePayRequest,
|
||||||
codecForPreparePayResultPaymentPossible,
|
|
||||||
codecForPreparePayResult,
|
codecForPreparePayResult,
|
||||||
OperationFailedError,
|
OperationFailedError,
|
||||||
AddExchangeRequest,
|
AddExchangeRequest,
|
||||||
@ -67,6 +66,8 @@ import {
|
|||||||
codecForTransactionsResponse,
|
codecForTransactionsResponse,
|
||||||
WithdrawTestBalanceRequest,
|
WithdrawTestBalanceRequest,
|
||||||
AmountString,
|
AmountString,
|
||||||
|
ApplyRefundRequest,
|
||||||
|
codecForApplyRefundResponse,
|
||||||
} from "taler-wallet-core";
|
} from "taler-wallet-core";
|
||||||
import { URL } from "url";
|
import { URL } from "url";
|
||||||
import axios, { AxiosError } from "axios";
|
import axios, { AxiosError } from "axios";
|
||||||
@ -77,6 +78,7 @@ import {
|
|||||||
PostOrderResponse,
|
PostOrderResponse,
|
||||||
MerchantOrderPrivateStatusResponse,
|
MerchantOrderPrivateStatusResponse,
|
||||||
} from "./merchantApiTypes";
|
} from "./merchantApiTypes";
|
||||||
|
import { ApplyRefundResponse } from "taler-wallet-core";
|
||||||
|
|
||||||
const exec = util.promisify(require("child_process").exec);
|
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 {
|
private shutdownSync(): void {
|
||||||
for (const s of this.servers) {
|
for (const s of this.servers) {
|
||||||
s.close();
|
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> {
|
async preparePay(req: PreparePayRequest): Promise<PreparePayResult> {
|
||||||
const resp = await this.apiRequest("preparePay", req);
|
const resp = await this.apiRequest("preparePay", req);
|
||||||
if (resp.type === "response") {
|
if (resp.type === "response") {
|
||||||
|
@ -83,8 +83,8 @@ export const codecForCheckPaymentPaidResponse = (): Codec<
|
|||||||
> =>
|
> =>
|
||||||
buildCodecForObject<CheckPaymentPaidResponse>()
|
buildCodecForObject<CheckPaymentPaidResponse>()
|
||||||
.property("order_status", codecForConstString("paid"))
|
.property("order_status", codecForConstString("paid"))
|
||||||
.property("refunded", codecForBoolean)
|
.property("refunded", codecForBoolean())
|
||||||
.property("wired", codecForBoolean)
|
.property("wired", codecForBoolean())
|
||||||
.property("deposit_total", codecForAmountString())
|
.property("deposit_total", codecForAmountString())
|
||||||
.property("exchange_ec", codecForNumber())
|
.property("exchange_ec", codecForNumber())
|
||||||
.property("exchange_hc", codecForNumber())
|
.property("exchange_hc", codecForNumber())
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
MerchantPrivateApi,
|
MerchantPrivateApi,
|
||||||
} from "./harness";
|
} from "./harness";
|
||||||
import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
|
import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
|
||||||
|
import { TransactionType, Amounts } from "taler-wallet-core";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run test for basic, bank-integrated withdrawal.
|
* Run test for basic, bank-integrated withdrawal.
|
||||||
@ -47,7 +48,7 @@ runTest(async (t: GlobalTestState) => {
|
|||||||
const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
|
const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
|
||||||
order: {
|
order: {
|
||||||
summary: "Buy me!",
|
summary: "Buy me!",
|
||||||
amount: "TESTKUDOS:5",
|
amount: "TESTKUDOS:10",
|
||||||
fulfillment_url: "taler://fulfillment-success/thx",
|
fulfillment_url: "taler://fulfillment-success/thx",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -88,9 +89,21 @@ runTest(async (t: GlobalTestState) => {
|
|||||||
|
|
||||||
console.log("first refund increase response", ref);
|
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
|
// Wait at least a second, because otherwise the increased
|
||||||
// refund will be grouped with the previous one.
|
// refund will be grouped with the previous one.
|
||||||
await delayMs(1.2);
|
await delayMs(1200);
|
||||||
|
|
||||||
ref = await MerchantPrivateApi.giveRefund(merchant, {
|
ref = await MerchantPrivateApi.giveRefund(merchant, {
|
||||||
amount: "TESTKUDOS:5",
|
amount: "TESTKUDOS:5",
|
||||||
@ -101,10 +114,25 @@ runTest(async (t: GlobalTestState) => {
|
|||||||
|
|
||||||
console.log("second refund increase response", ref);
|
console.log("second refund increase response", ref);
|
||||||
|
|
||||||
let r = await wallet.apiRequest("applyRefund", {
|
// 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("third refund increase response", ref);
|
||||||
|
|
||||||
|
{
|
||||||
|
let wr = await wallet.applyRefund({
|
||||||
talerRefundUri: ref.talerRefundUri,
|
talerRefundUri: ref.talerRefundUri,
|
||||||
});
|
});
|
||||||
console.log(r);
|
console.log(wr);
|
||||||
|
}
|
||||||
|
|
||||||
orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
|
orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
|
||||||
orderId: orderResp.order_id,
|
orderId: orderResp.order_id,
|
||||||
@ -112,17 +140,43 @@ runTest(async (t: GlobalTestState) => {
|
|||||||
|
|
||||||
t.assertTrue(orderStatus.order_status === "paid");
|
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));
|
console.log(JSON.stringify(orderStatus, undefined, 2));
|
||||||
|
|
||||||
await wallet.runUntilDone();
|
await wallet.runUntilDone();
|
||||||
|
|
||||||
r = await wallet.apiRequest("getBalances", {});
|
const bal = await wallet.getBalances();
|
||||||
console.log(JSON.stringify(r, undefined, 2));
|
console.log(JSON.stringify(bal, undefined, 2));
|
||||||
|
|
||||||
r = await wallet.apiRequest("getTransactions", {});
|
{
|
||||||
console.log(JSON.stringify(r, 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();
|
await t.shutdown();
|
||||||
});
|
});
|
||||||
|
@ -281,22 +281,27 @@ export async function getTransactions(
|
|||||||
groupKey,
|
groupKey,
|
||||||
);
|
);
|
||||||
let r0: WalletRefundItem | undefined;
|
let r0: WalletRefundItem | undefined;
|
||||||
let amountEffective = Amounts.getZero(
|
let amountRaw = Amounts.getZero(
|
||||||
pr.contractData.amount.currency,
|
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)) {
|
for (const rk of Object.keys(pr.refunds)) {
|
||||||
const refund = pr.refunds[rk];
|
const refund = pr.refunds[rk];
|
||||||
|
const myGroupKey = `${refund.executionTime.t_ms}`;
|
||||||
|
if (myGroupKey !== groupKey) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!r0) {
|
if (!r0) {
|
||||||
r0 = refund;
|
r0 = refund;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refund.type === RefundState.Applied) {
|
if (refund.type === RefundState.Applied) {
|
||||||
amountEffective = Amounts.add(
|
|
||||||
amountEffective,
|
|
||||||
refund.refundAmount,
|
|
||||||
).amount;
|
|
||||||
amountRaw = Amounts.add(
|
amountRaw = Amounts.add(
|
||||||
amountRaw,
|
amountRaw,
|
||||||
|
refund.refundAmount,
|
||||||
|
).amount;
|
||||||
|
amountEffective = Amounts.add(
|
||||||
|
amountEffective,
|
||||||
Amounts.sub(
|
Amounts.sub(
|
||||||
refund.refundAmount,
|
refund.refundAmount,
|
||||||
refund.refundFee,
|
refund.refundFee,
|
||||||
|
@ -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) {
|
if (amounts.length <= 0) {
|
||||||
throw Error("can't sum zero amounts");
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user