summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-08-10 16:48:38 +0530
committerFlorian Dold <florian.dold@gmail.com>2020-08-10 16:48:38 +0530
commit66d76a35912d7687d76b349f1cac462306306d3f (patch)
tree3cdfce8178c3928dbcfc13263f8752b3f9ca9c7b /packages/taler-wallet-core
parent5f8714091aac80144be118fa6427d65222e7509c (diff)
downloadwallet-core-66d76a35912d7687d76b349f1cac462306306d3f.tar.gz
wallet-core-66d76a35912d7687d76b349f1cac462306306d3f.tar.bz2
wallet-core-66d76a35912d7687d76b349f1cac462306306d3f.zip
simplify refunds a bit, show in transaction history, add integration tests
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r--packages/taler-wallet-core/src/operations/refund.ts60
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts86
-rw-r--r--packages/taler-wallet-core/src/types/transactions.ts5
3 files changed, 103 insertions, 48 deletions
diff --git a/packages/taler-wallet-core/src/operations/refund.ts b/packages/taler-wallet-core/src/operations/refund.ts
index 9792d2268..2b6ee97ae 100644
--- a/packages/taler-wallet-core/src/operations/refund.ts
+++ b/packages/taler-wallet-core/src/operations/refund.ts
@@ -203,7 +203,7 @@ async function acceptRefunds(
refunds: MerchantCoinRefundStatus[],
reason: RefundReason,
): Promise<void> {
- console.log("handling refunds", refunds);
+ logger.trace("handling refunds", refunds);
const now = getTimestampNow();
await ws.db.runWithWriteTransaction(
@@ -302,37 +302,6 @@ async function acceptRefunds(
});
}
-async function startRefundQuery(
- ws: InternalWalletState,
- proposalId: string,
-): Promise<void> {
- const success = await ws.db.runWithWriteTransaction(
- [Stores.purchases],
- async (tx) => {
- const p = await tx.get(Stores.purchases, proposalId);
- if (!p) {
- logger.error("no purchase found for refund URL");
- return false;
- }
- p.refundStatusRequested = true;
- p.lastRefundStatusError = undefined;
- p.refundStatusRetryInfo = initRetryInfo();
- await tx.put(Stores.purchases, p);
- return true;
- },
- );
-
- if (!success) {
- return;
- }
-
- ws.notify({
- type: NotificationType.RefundStarted,
- });
-
- await processPurchaseQueryRefund(ws, proposalId);
-}
-
/**
* Accept a refund, return the contract hash for the contract
* that was involved in the refund.
@@ -360,8 +329,31 @@ export async function applyRefund(
);
}
+ const proposalId = purchase.proposalId;
+
logger.info("processing purchase for refund");
- await startRefundQuery(ws, purchase.proposalId);
+ const success = await ws.db.runWithWriteTransaction(
+ [Stores.purchases],
+ async (tx) => {
+ const p = await tx.get(Stores.purchases, proposalId);
+ if (!p) {
+ logger.error("no purchase found for refund URL");
+ return false;
+ }
+ p.refundStatusRequested = true;
+ p.lastRefundStatusError = undefined;
+ p.refundStatusRetryInfo = initRetryInfo();
+ await tx.put(Stores.purchases, p);
+ return true;
+ },
+ );
+
+ if (success) {
+ ws.notify({
+ type: NotificationType.RefundStarted,
+ });
+ await processPurchaseQueryRefund(ws, proposalId);
+ }
return {
contractTermsHash: purchase.contractData.contractTermsHash,
@@ -422,7 +414,7 @@ async function processPurchaseQueryRefundImpl(
const request = await ws.http.get(requestUrl.href);
- console.log("got json", JSON.stringify(await request.json(), undefined, 2));
+ logger.trace("got json", JSON.stringify(await request.json(), undefined, 2));
const refundResponse = await readSuccessResponseJsonOrThrow(
request,
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 2d66b5e9d..8de204d49 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -18,7 +18,12 @@
* Imports.
*/
import { InternalWalletState } from "./state";
-import { Stores, WithdrawalSourceType } from "../types/dbTypes";
+import {
+ Stores,
+ WithdrawalSourceType,
+ WalletRefundItem,
+ RefundState,
+} from "../types/dbTypes";
import { Amounts, AmountJson } from "../util/amounts";
import { timestampCmp } from "../util/time";
import {
@@ -29,8 +34,10 @@ import {
PaymentStatus,
WithdrawalType,
WithdrawalDetails,
+ PaymentShortInfo,
} from "../types/transactions";
import { getFundingPaytoUris } from "./reserves";
+import { ResultLevel } from "idb-bridge";
/**
* Create an event ID from the type and the primary key for the event.
@@ -224,6 +231,18 @@ export async function getTransactions(
if (!proposal) {
return;
}
+ const info: PaymentShortInfo = {
+ fulfillmentUrl: pr.contractData.fulfillmentUrl,
+ merchant: pr.contractData.merchant,
+ orderId: pr.contractData.orderId,
+ products: pr.contractData.products,
+ summary: pr.contractData.summary,
+ summary_i18n: pr.contractData.summaryI18n,
+ };
+ const paymentTransactionId = makeEventId(
+ TransactionType.Payment,
+ pr.proposalId,
+ );
transactions.push({
type: TransactionType.Payment,
amountRaw: Amounts.stringify(pr.contractData.amount),
@@ -233,15 +252,62 @@ export async function getTransactions(
: PaymentStatus.Accepted,
pending: !pr.timestampFirstSuccessfulPay,
timestamp: pr.timestampAccept,
- transactionId: makeEventId(TransactionType.Payment, pr.proposalId),
- info: {
- fulfillmentUrl: pr.contractData.fulfillmentUrl,
- merchant: pr.contractData.merchant,
- orderId: pr.contractData.orderId,
- products: pr.contractData.products,
- summary: pr.contractData.summary,
- summary_i18n: pr.contractData.summaryI18n,
- },
+ transactionId: paymentTransactionId,
+ info: info,
+ });
+
+ const refundGroupKeys = new Set<string>();
+
+ for (const rk of Object.keys(pr.refunds)) {
+ const refund = pr.refunds[rk];
+ const groupKey = `${refund.executionTime.t_ms}`;
+ refundGroupKeys.add(groupKey);
+ }
+
+ refundGroupKeys.forEach((groupKey: string) => {
+ const refundTransactionId = makeEventId(
+ TransactionType.Payment,
+ pr.proposalId,
+ groupKey,
+ );
+ let r0: WalletRefundItem | undefined;
+ let amountEffective = Amounts.getZero(
+ pr.contractData.amount.currency,
+ );
+ let amountRaw = Amounts.getZero(pr.contractData.amount.currency);
+ for (const rk of Object.keys(pr.refunds)) {
+ const refund = pr.refunds[rk];
+ if (!r0) {
+ r0 = refund;
+ }
+ if (refund.type === RefundState.Applied) {
+ amountEffective = Amounts.add(
+ amountEffective,
+ refund.refundAmount,
+ ).amount;
+ amountRaw = Amounts.add(
+ amountRaw,
+ Amounts.sub(
+ refund.refundAmount,
+ refund.refundFee,
+ refund.totalRefreshCostBound,
+ ).amount,
+ ).amount;
+ }
+ }
+ if (!r0) {
+ throw Error("invariant violated");
+ }
+ transactions.push({
+ type: TransactionType.Refund,
+ info,
+ refundedTransactionId: paymentTransactionId,
+ transactionId: refundTransactionId,
+ timestamp: r0.executionTime,
+ amountEffective: Amounts.stringify(amountEffective),
+ amountRaw: Amounts.stringify(amountRaw),
+ pending: false,
+ });
});
// for (const rg of pr.refundGroups) {
diff --git a/packages/taler-wallet-core/src/types/transactions.ts b/packages/taler-wallet-core/src/types/transactions.ts
index de378f51a..fe5580f85 100644
--- a/packages/taler-wallet-core/src/types/transactions.ts
+++ b/packages/taler-wallet-core/src/types/transactions.ts
@@ -218,7 +218,7 @@ export interface TransactionPayment extends TransactionCommon {
amountEffective: AmountString;
}
-interface PaymentShortInfo {
+export interface PaymentShortInfo {
/**
* Order ID, uniquely identifies the order within a merchant instance
*/
@@ -259,9 +259,6 @@ interface TransactionRefund extends TransactionCommon {
// Additional information about the refunded payment
info: PaymentShortInfo;
- // Part of the refund that couldn't be applied because the refund permissions were expired
- amountInvalid: AmountString;
-
// Amount that has been refunded by the merchant
amountRaw: AmountString;