aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/operations/transactions.ts80
-rw-r--r--src/types/transactions.ts24
2 files changed, 85 insertions, 19 deletions
diff --git a/src/operations/transactions.ts b/src/operations/transactions.ts
index 5e4de4188..4cc6154b5 100644
--- a/src/operations/transactions.ts
+++ b/src/operations/transactions.ts
@@ -18,7 +18,7 @@
* Imports.
*/
import { InternalWalletState } from "./state";
-import { Stores, ReserveRecordStatus, PurchaseRecord } from "../types/dbTypes";
+import { Stores, ReserveRecordStatus, PurchaseRecord, ProposalStatus } from "../types/dbTypes";
import { Amounts, AmountJson } from "../util/amounts";
import { timestampCmp } from "../util/time";
import {
@@ -26,8 +26,8 @@ import {
TransactionsResponse,
Transaction,
TransactionType,
+ PaymentStatus,
} from "../types/transactions";
-import { getTotalPaymentCost } from "./pay";
/**
* Create an event ID from the type and the primary key for the event.
@@ -36,14 +36,16 @@ function makeEventId(type: TransactionType, ...args: string[]): string {
return type + ";" + args.map((x) => encodeURIComponent(x)).join(";");
}
-
interface RefundStats {
amountInvalid: AmountJson;
amountEffective: AmountJson;
amountRaw: AmountJson;
}
-function getRefundStats(pr: PurchaseRecord, refundGroupId: string): RefundStats {
+function getRefundStats(
+ pr: PurchaseRecord,
+ refundGroupId: string,
+): RefundStats {
let amountEffective = Amounts.getZero(pr.contractData.amount.currency);
let amountInvalid = Amounts.getZero(pr.contractData.amount.currency);
let amountRaw = Amounts.getZero(pr.contractData.amount.currency);
@@ -53,8 +55,12 @@ function getRefundStats(pr: PurchaseRecord, refundGroupId: string): RefundStats
if (pr.refundsDone[rk].refundGroupId !== refundGroupId) {
continue;
}
- amountEffective = Amounts.add(amountEffective, Amounts.parseOrThrow(perm.refund_amount)).amount;
- amountRaw = Amounts.add(amountRaw, Amounts.parseOrThrow(perm.refund_amount)).amount;
+ amountEffective = Amounts.add(
+ amountEffective,
+ Amounts.parseOrThrow(perm.refund_amount),
+ ).amount;
+ amountRaw = Amounts.add(amountRaw, Amounts.parseOrThrow(perm.refund_amount))
+ .amount;
}
for (const rk of Object.keys(pr.refundsDone)) {
@@ -62,7 +68,10 @@ function getRefundStats(pr: PurchaseRecord, refundGroupId: string): RefundStats
if (pr.refundsDone[rk].refundGroupId !== refundGroupId) {
continue;
}
- amountEffective = Amounts.sub(amountEffective, Amounts.parseOrThrow(perm.refund_fee)).amount;
+ amountEffective = Amounts.sub(
+ amountEffective,
+ Amounts.parseOrThrow(perm.refund_fee),
+ ).amount;
}
for (const rk of Object.keys(pr.refundsFailed)) {
@@ -70,15 +79,17 @@ function getRefundStats(pr: PurchaseRecord, refundGroupId: string): RefundStats
if (pr.refundsDone[rk].refundGroupId !== refundGroupId) {
continue;
}
- amountInvalid = Amounts.add(amountInvalid, Amounts.parseOrThrow(perm.refund_fee)).amount;
+ amountInvalid = Amounts.add(
+ amountInvalid,
+ Amounts.parseOrThrow(perm.refund_fee),
+ ).amount;
}
return {
amountEffective,
amountInvalid,
amountRaw,
- }
-
+ };
}
/**
@@ -165,6 +176,38 @@ export async function getTransactions(
});
});
+ tx.iter(Stores.proposals).forEachAsync(async (proposal) => {
+ if (!proposal.download) {
+ return;
+ }
+ if (proposal.proposalStatus !== ProposalStatus.PROPOSED) {
+ return;
+ }
+ const dl = proposal.download;
+ const purchase = await tx.get(Stores.purchases, proposal.proposalId);
+ if (purchase) {
+ return;
+ }
+
+ transactions.push({
+ type: TransactionType.Payment,
+ amountRaw: Amounts.stringify(dl.contractData.amount),
+ amountEffective: undefined,
+ status: PaymentStatus.Offered,
+ pending: true,
+ timestamp: proposal.timestamp,
+ transactionId: makeEventId(TransactionType.Payment, proposal.proposalId),
+ info: {
+ fulfillmentUrl: dl.contractData.fulfillmentUrl,
+ merchant: {},
+ orderId: dl.contractData.orderId,
+ products: [],
+ summary: dl.contractData.summary,
+ summary_i18n: {},
+ },
+ });
+ });
+
tx.iter(Stores.purchases).forEachAsync(async (pr) => {
if (
transactionsRequest?.currency &&
@@ -180,7 +223,9 @@ export async function getTransactions(
type: TransactionType.Payment,
amountRaw: Amounts.stringify(pr.contractData.amount),
amountEffective: Amounts.stringify(pr.payCostInfo.totalCost),
- failed: false,
+ status: pr.timestampFirstSuccessfulPay
+ ? PaymentStatus.Paid
+ : PaymentStatus.Accepted,
pending: !pr.timestampFirstSuccessfulPay,
timestamp: pr.timestampAccept,
transactionId: makeEventId(TransactionType.Payment, pr.proposalId),
@@ -198,7 +243,7 @@ export async function getTransactions(
const pending = Object.keys(pr.refundsDone).length > 0;
const stats = getRefundStats(pr, rg.refundGroupId);
-
+
transactions.push({
type: TransactionType.Refund,
pending,
@@ -211,12 +256,17 @@ export async function getTransactions(
summary_i18n: {},
},
timestamp: rg.timestampQueried,
- transactionId: makeEventId(TransactionType.Refund, `{rg.timestampQueried.t_ms}`),
- refundedTransactionId: makeEventId(TransactionType.Payment, pr.proposalId),
+ transactionId: makeEventId(
+ TransactionType.Refund,
+ `{rg.timestampQueried.t_ms}`,
+ ),
+ refundedTransactionId: makeEventId(
+ TransactionType.Payment,
+ pr.proposalId,
+ ),
amountEffective: Amounts.stringify(stats.amountEffective),
amountInvalid: Amounts.stringify(stats.amountInvalid),
amountRaw: Amounts.stringify(stats.amountRaw),
-
});
}
});
diff --git a/src/types/transactions.ts b/src/types/transactions.ts
index 7dda46f73..263e08a4e 100644
--- a/src/types/transactions.ts
+++ b/src/types/transactions.ts
@@ -111,15 +111,31 @@ interface TransactionWithdrawal extends TransactionCommon {
amountEffective?: AmountString;
}
-interface TransactionPayment extends TransactionCommon {
+export const enum PaymentStatus {
+ // Explicitly aborted after timeout / failure
+ Aborted = "aborted",
+
+ // Payment failed, wallet will auto-retry.
+ // User should be given the option to retry now / abort.
+ Failed = "failed",
+
+ // Paid successfully
+ Paid = "paid",
+
+ // Only offered, user must accept / decline
+ Offered = "offered",
+
+ // User accepted, payment is processing.
+ Accepted = "accepted",
+}
+
+export interface TransactionPayment extends TransactionCommon {
type: TransactionType.Payment;
// Additional information about the payment.
info: PaymentShortInfo;
- // true if the payment failed, false otherwise.
- // Note that failed payments with zero effective amount will not be returned by the API.
- failed: boolean;
+ status: PaymentStatus;
// Amount that must be paid for the contract
amountRaw: AmountString;