commit fa0b2336d29ef7419158b647b3f304aaf5bc87f2
parent 4554fb0fb2575958fd5f47615067dbde6aea148b
Author: Florian Dold <dold@taler.net>
Date: Sat, 18 Jul 2026 21:16:14 +0200
db: add purchase and refund accessors
Diffstat:
9 files changed, 547 insertions(+), 392 deletions(-)
diff --git a/packages/taler-wallet-core/src/common.ts b/packages/taler-wallet-core/src/common.ts
@@ -72,6 +72,7 @@ import {
WalletRecoupGroup,
WalletRefreshGroup,
WalletWithdrawalGroup,
+ WalletPurchase,
} from "./db-common.js";
import {
ExchangeEntryRecord,
@@ -79,7 +80,6 @@ import {
PeerPullPaymentIncomingRecord,
PeerPushCreditRecord,
PeerPushDebitRecord,
- PurchaseRecord,
} from "./db-indexeddb.js";
import { WalletDbTransaction } from "./dbtx.js";
import { ReadyExchangeSummary } from "./exchanges.js";
@@ -826,7 +826,7 @@ export namespace TaskIdentifiers {
): TaskIdStr {
return `${PendingTaskType.Refresh}:${refreshGroupRecord.refreshGroupId}` as TaskIdStr;
}
- export function forPay(purchaseRecord: PurchaseRecord): TaskIdStr {
+ export function forPay(purchaseRecord: WalletPurchase): TaskIdStr {
return `${PendingTaskType.Purchase}:${purchaseRecord.proposalId}` as TaskIdStr;
}
export function forRecoup(recoupRecord: WalletRecoupGroup): TaskIdStr {
diff --git a/packages/taler-wallet-core/src/db-common.ts b/packages/taler-wallet-core/src/db-common.ts
@@ -40,6 +40,7 @@ import {
DonationReceiptSignature,
HashCodeString,
BlindedUniqueDonationIdentifier,
+ SignedTokenEnvelope,
CoinStatus,
AgeCommitmentProof,
TransactionIdStr,
@@ -829,6 +830,282 @@ export interface WalletDonationPlanchet {
value: AmountString;
}
+/**
+ * Partial information about the downloaded proposal.
+ * Only contains data that is relevant for indexing on the
+ * "purchases" object stores.
+ */
+export interface WalletProposalDownloadInfo {
+ contractTermsHash: string;
+ fulfillmentUrl?: string;
+ currency: string;
+ contractTermsMerchantSig: string;
+}
+
+export interface WalletTokenSelection {
+ tokenPubs: string[];
+}
+
+export interface WalletPurchasePayInfo {
+ /**
+ * Undefined if payment is blocked by a pending refund.
+ */
+ payCoinSelection?: WalletCoinSelection;
+ /**
+ * Undefined if payment is blocked by a pending refund.
+ */
+ payCoinSelectionUid?: string;
+
+ payTokenSelection?: WalletTokenSelection;
+
+ /**
+ * Token signatures from merchant.
+ */
+ slateTokenSigs?: SignedTokenEnvelope[];
+
+ /**
+ * Whether token selection should be forced
+ * e.g. when merchant URL is not in `expected_domains'
+ */
+ payTokenForcedSel?: boolean;
+
+ totalPayCost: AmountString;
+}
+
+/**
+ * Record that stores status information about one purchase, starting from when
+ * the customer accepts a proposal. Includes refund status if applicable.
+ *
+ * Key: {@link proposalId}
+ * Operation status: {@link purchaseStatus}
+ */
+export interface WalletPurchase {
+ /**
+ * Proposal ID for this purchase. Uniquely identifies the
+ * purchase and the proposal.
+ * Assigned by the wallet.
+ */
+ proposalId: string;
+
+ /**
+ * Order ID, assigned by the merchant.
+ */
+ orderId: string;
+
+ merchantBaseUrl: string;
+
+ /**
+ * Claim token used when downloading the contract terms.
+ */
+ claimToken: string | undefined;
+
+ /**
+ * Session ID we got when downloading the contract.
+ */
+ downloadSessionId: string | undefined;
+
+ /**
+ * If this purchase is a repurchase, this field identifies the original purchase.
+ */
+ repurchaseProposalId: string | undefined;
+
+ purchaseStatus: PurchaseStatus;
+
+ /**
+ * Refresh group ID of the refresh transaction that
+ * has been created to abort the payment.
+ */
+ abortRefreshGroupId?: string;
+
+ abortReason?: TalerErrorDetail;
+ failReason?: TalerErrorDetail;
+
+ /**
+ * Private key for the nonce.
+ */
+ noncePriv: string;
+
+ /**
+ * Public key for the nonce.
+ */
+ noncePub: string;
+
+ /**
+ * Index of selected choice in the choices array.
+ */
+ choiceIndex?: number | undefined;
+
+ /**
+ * Secret seed used to derive slates.
+ * Stored since slates are created lazily.
+ */
+ secretSeed: string | undefined;
+
+ /**
+ * Downloaded and parsed proposal data.
+ */
+ download: WalletProposalDownloadInfo | undefined;
+
+ payInfo: WalletPurchasePayInfo | undefined;
+
+ /**
+ * Exchanges involved in this purchase.
+ * Used as a multiEntry index to find all purchases for
+ * an exchange.
+ */
+ exchanges?: string[];
+
+ /**
+ * Pending removals from pay coin selection.
+ *
+ * Used when a the pay coin selection needs to be changed
+ * because a coin became known as double-spent or invalid,
+ * but a new coin selection can't immediately be done, as
+ * there is not enough balance (e.g. when waiting for a refresh).
+ */
+ pendingRemovedCoinPubs?: string[];
+
+ /**
+ * Timestamp of the first time that sending a payment to the merchant
+ * for this purchase was successful.
+ */
+ timestampFirstSuccessfulPay: DbPreciseTimestamp | undefined;
+
+ merchantPaySig: string | undefined;
+
+ posConfirmation: string | undefined;
+
+ donauOutputIndex?: number;
+ donauBaseUrl?: string;
+ donauAmount?: AmountString;
+ donauTaxIdHash?: string;
+ donauTaxIdSalt?: string;
+ donauTaxId?: string;
+ donauYear?: number;
+
+ /**
+ * This purchase was shared with another wallet
+ * that is now supposed to finish the payment.
+ */
+ shared: boolean;
+
+ /**
+ * This purchase was created by reading
+ * a payment share or the wallet
+ * the nonce public by a payment share
+ *
+ * Defaults to false.
+ */
+ createdFromShared?: boolean;
+
+ /**
+ * When was the purchase record created?
+ */
+ timestamp: DbPreciseTimestamp;
+
+ /**
+ * When was the purchase made?
+ * Refers to the time that the user accepted.
+ */
+ timestampAccept: DbPreciseTimestamp | undefined;
+
+ /**
+ * When was the last refund made?
+ * Set to 0 if no refund was made on the purchase.
+ */
+ timestampLastRefundStatus: DbPreciseTimestamp | undefined;
+
+ /**
+ * Timestamp when the wallet noticed that the transaction expired.
+ * May be later than the pay deadline.
+ */
+ timestampExpired?: DbPreciseTimestamp;
+
+ /**
+ * Last session signature that we submitted to /pay (if any).
+ */
+ lastSessionId: string | undefined;
+
+ /**
+ * Continue querying the refund status until this deadline has expired.
+ */
+ autoRefundDeadline: DbProtocolTimestamp | undefined;
+
+ /**
+ * How much merchant has refund to be taken but the wallet
+ * did not picked up yet
+ */
+ refundAmountAwaiting: AmountString | undefined;
+}
+
+/**
+ * Metadata about a group of refunds with the merchant.
+ */
+export interface WalletRefundGroup {
+ status: RefundGroupStatus;
+
+ /**
+ * Timestamp when the refund group was created.
+ */
+ timestampCreated: DbPreciseTimestamp;
+
+ proposalId: string;
+
+ refundGroupId: string;
+
+ refreshGroupId?: string;
+
+ amountRaw: AmountString;
+
+ /**
+ * Estimated effective amount, based on
+ * refund fees and refresh costs.
+ */
+ amountEffective: AmountString;
+}
+
+/**
+ * Refund for a single coin in a payment with a merchant.
+ */
+export interface WalletRefundItem {
+ /**
+ * Auto-increment DB record ID.
+ */
+ id?: number;
+
+ status: RefundItemStatus;
+
+ /**
+ * Mandatory since DB minor version 15.
+ */
+ proposalId?: string;
+
+ refundGroupId: string;
+
+ /**
+ * Execution time as claimed by the merchant
+ */
+ executionTime: DbProtocolTimestamp;
+
+ /**
+ * Time when the wallet became aware of the refund.
+ */
+ obtainedTime: DbPreciseTimestamp;
+
+ refundAmount: AmountString;
+
+ coinPub: string;
+
+ rtxid: number;
+}
+
+export interface WalletTombstone {
+ /**
+ * Tombstone ID, with the syntax "tmb:<type>:<key>".
+ */
+ id: string;
+}
+
export interface WalletWithdrawCoinSource {
type: CoinSourceType.Withdraw;
diff --git a/packages/taler-wallet-core/src/db-indexeddb.ts b/packages/taler-wallet-core/src/db-indexeddb.ts
@@ -134,6 +134,13 @@ import {
WalletWithdrawalGroup,
WalletPlanchet,
WalletDonationSummary,
+ WalletProposalDownloadInfo,
+ WalletTokenSelection,
+ WalletPurchasePayInfo,
+ WalletPurchase,
+ WalletRefundGroup,
+ WalletRefundItem,
+ WalletTombstone,
WalletDonationReceipt,
WalletDonationPlanchet,
WalletRefreshSession,
@@ -634,214 +641,6 @@ export namespace TokenRecord {
}
}
-/**
- * Partial information about the downloaded proposal.
- * Only contains data that is relevant for indexing on the
- * "purchases" object stores.
- */
-export interface ProposalDownloadInfo {
- contractTermsHash: string;
- fulfillmentUrl?: string;
- currency: string;
- contractTermsMerchantSig: string;
-}
-
-export interface DbTokenSelection {
- tokenPubs: string[];
-}
-
-export interface PurchasePayInfo {
- /**
- * Undefined if payment is blocked by a pending refund.
- */
- payCoinSelection?: WalletCoinSelection;
- /**
- * Undefined if payment is blocked by a pending refund.
- */
- payCoinSelectionUid?: string;
-
- payTokenSelection?: DbTokenSelection;
-
- /**
- * Token signatures from merchant.
- */
- slateTokenSigs?: SignedTokenEnvelope[];
-
- /**
- * Whether token selection should be forced
- * e.g. when merchant URL is not in `expected_domains'
- */
- payTokenForcedSel?: boolean;
-
- totalPayCost: AmountString;
-}
-
-/**
- * Record that stores status information about one purchase, starting from when
- * the customer accepts a proposal. Includes refund status if applicable.
- *
- * Key: {@link proposalId}
- * Operation status: {@link purchaseStatus}
- */
-export interface PurchaseRecord {
- /**
- * Proposal ID for this purchase. Uniquely identifies the
- * purchase and the proposal.
- * Assigned by the wallet.
- */
- proposalId: string;
-
- /**
- * Order ID, assigned by the merchant.
- */
- orderId: string;
-
- merchantBaseUrl: string;
-
- /**
- * Claim token used when downloading the contract terms.
- */
- claimToken: string | undefined;
-
- /**
- * Session ID we got when downloading the contract.
- */
- downloadSessionId: string | undefined;
-
- /**
- * If this purchase is a repurchase, this field identifies the original purchase.
- */
- repurchaseProposalId: string | undefined;
-
- purchaseStatus: PurchaseStatus;
-
- /**
- * Refresh group ID of the refresh transaction that
- * has been created to abort the payment.
- */
- abortRefreshGroupId?: string;
-
- abortReason?: TalerErrorDetail;
- failReason?: TalerErrorDetail;
-
- /**
- * Private key for the nonce.
- */
- noncePriv: string;
-
- /**
- * Public key for the nonce.
- */
- noncePub: string;
-
- /**
- * Index of selected choice in the choices array.
- */
- choiceIndex?: number | undefined;
-
- /**
- * Secret seed used to derive slates.
- * Stored since slates are created lazily.
- */
- secretSeed: string | undefined;
-
- /**
- * Downloaded and parsed proposal data.
- */
- download: ProposalDownloadInfo | undefined;
-
- payInfo: PurchasePayInfo | undefined;
-
- /**
- * Exchanges involved in this purchase.
- * Used as a multiEntry index to find all purchases for
- * an exchange.
- */
- exchanges?: string[];
-
- /**
- * Pending removals from pay coin selection.
- *
- * Used when a the pay coin selection needs to be changed
- * because a coin became known as double-spent or invalid,
- * but a new coin selection can't immediately be done, as
- * there is not enough balance (e.g. when waiting for a refresh).
- */
- pendingRemovedCoinPubs?: string[];
-
- /**
- * Timestamp of the first time that sending a payment to the merchant
- * for this purchase was successful.
- */
- timestampFirstSuccessfulPay: DbPreciseTimestamp | undefined;
-
- merchantPaySig: string | undefined;
-
- posConfirmation: string | undefined;
-
- donauOutputIndex?: number;
- donauBaseUrl?: string;
- donauAmount?: AmountString;
- donauTaxIdHash?: string;
- donauTaxIdSalt?: string;
- donauTaxId?: string;
- donauYear?: number;
-
- /**
- * This purchase was shared with another wallet
- * that is now supposed to finish the payment.
- */
- shared: boolean;
-
- /**
- * This purchase was created by reading
- * a payment share or the wallet
- * the nonce public by a payment share
- *
- * Defaults to false.
- */
- createdFromShared?: boolean;
-
- /**
- * When was the purchase record created?
- */
- timestamp: DbPreciseTimestamp;
-
- /**
- * When was the purchase made?
- * Refers to the time that the user accepted.
- */
- timestampAccept: DbPreciseTimestamp | undefined;
-
- /**
- * When was the last refund made?
- * Set to 0 if no refund was made on the purchase.
- */
- timestampLastRefundStatus: DbPreciseTimestamp | undefined;
-
- /**
- * Timestamp when the wallet noticed that the transaction expired.
- * May be later than the pay deadline.
- */
- timestampExpired?: DbPreciseTimestamp;
-
- /**
- * Last session signature that we submitted to /pay (if any).
- */
- lastSessionId: string | undefined;
-
- /**
- * Continue querying the refund status until this deadline has expired.
- */
- autoRefundDeadline: DbProtocolTimestamp | undefined;
-
- /**
- * How much merchant has refund to be taken but the wallet
- * did not picked up yet
- */
- refundAmountAwaiting: AmountString | undefined;
-}
-
// FIXME: Should these be numeric codes?
export type KycUserType = "individual" | "business";
@@ -857,13 +656,6 @@ export interface BankWithdrawUriRecord {
reservePub: string;
}
-export interface TombstoneRecord {
- /**
- * Tombstone ID, with the syntax "tmb:<type>:<key>".
- */
- id: string;
-}
-
export interface DbPeerPushPaymentCoinSelection {
contributions: AmountString[];
coinPubs: CoinPublicKeyString[];
@@ -1127,67 +919,6 @@ export interface DbAuditorHandle {
auditorPub: string;
}
-/**
- * Metadata about a group of refunds with the merchant.
- */
-export interface RefundGroupRecord {
- status: RefundGroupStatus;
-
- /**
- * Timestamp when the refund group was created.
- */
- timestampCreated: DbPreciseTimestamp;
-
- proposalId: string;
-
- refundGroupId: string;
-
- refreshGroupId?: string;
-
- amountRaw: AmountString;
-
- /**
- * Estimated effective amount, based on
- * refund fees and refresh costs.
- */
- amountEffective: AmountString;
-}
-
-/**
- * Refund for a single coin in a payment with a merchant.
- */
-export interface RefundItemRecord {
- /**
- * Auto-increment DB record ID.
- */
- id?: number;
-
- status: RefundItemStatus;
-
- /**
- * Mandatory since DB minor version 15.
- */
- proposalId?: string;
-
- refundGroupId: string;
-
- /**
- * Execution time as claimed by the merchant
- */
- executionTime: DbProtocolTimestamp;
-
- /**
- * Time when the wallet became aware of the refund.
- */
- obtainedTime: DbPreciseTimestamp;
-
- refundAmount: AmountString;
-
- coinPub: string;
-
- rtxid: number;
-}
-
export function passthroughCodec<T>(): Codec<T> {
return codecForAny();
}
@@ -1649,7 +1380,7 @@ export const WalletIndexedDbStoresV1 = {
),
purchases: describeStore(
"purchases",
- describeContents<PurchaseRecord>({ keyPath: "proposalId" }),
+ describeContents<WalletPurchase>({ keyPath: "proposalId" }),
{
byStatus: describeIndex("byStatus", "purchaseStatus"),
byFulfillmentUrl: describeIndex(
@@ -1756,7 +1487,7 @@ export const WalletIndexedDbStoresV1 = {
),
tombstones: describeStore(
"tombstones",
- describeContents<TombstoneRecord>({ keyPath: "id" }),
+ describeContents<WalletTombstone>({ keyPath: "id" }),
{},
),
operationRetries: describeStore(
@@ -1855,7 +1586,7 @@ export const WalletIndexedDbStoresV1 = {
),
refundGroups: describeStore(
"refundGroups",
- describeContents<RefundGroupRecord>({
+ describeContents<WalletRefundGroup>({
keyPath: "refundGroupId",
}),
{
@@ -1865,7 +1596,7 @@ export const WalletIndexedDbStoresV1 = {
),
refundItems: describeStore(
"refundItems",
- describeContents<RefundItemRecord>({
+ describeContents<WalletRefundItem>({
keyPath: "id",
autoIncrement: true,
}),
diff --git a/packages/taler-wallet-core/src/dbtx-indexeddb.ts b/packages/taler-wallet-core/src/dbtx-indexeddb.ts
@@ -65,13 +65,16 @@ import {
WalletDonationReceipt,
WalletDonationPlanchet,
DonationReceiptStatus,
+ WalletPurchase,
+ WalletRefundGroup,
+ WalletRefundItem,
+ WalletTombstone,
} from "./db-common.js";
import type {
ExchangeEntryRecord,
ExchangeDetailsRecord,
} from "./db-indexeddb.js";
import {
- PurchaseRecord,
WalletIndexedDbTransaction,
} from "./db-indexeddb.js";
import type {
@@ -216,7 +219,7 @@ export class IdbWalletTransaction implements WalletDbTransaction {
await tx.mailboxConfigurations.put(mailboxConf);
}
- async getPurchase(proposalId: string): Promise<PurchaseRecord | undefined> {
+ async getPurchase(proposalId: string): Promise<WalletPurchase | undefined> {
const tx = this.tx;
return await tx.purchases.get(proposalId);
}
@@ -273,6 +276,113 @@ export class IdbWalletTransaction implements WalletDbTransaction {
});
}
+ async upsertPurchase(rec: WalletPurchase): Promise<void> {
+ const tx = this.tx;
+ await tx.purchases.put(rec);
+ }
+
+ async deletePurchase(proposalId: string): Promise<void> {
+ const tx = this.tx;
+ await tx.purchases.delete(proposalId);
+ }
+
+ async getPurchaseByUrlAndOrderId(
+ merchantBaseUrl: string,
+ orderId: string,
+ ): Promise<WalletPurchase | undefined> {
+ const tx = this.tx;
+ return await tx.purchases.indexes.byUrlAndOrderId.get([
+ merchantBaseUrl,
+ orderId,
+ ]);
+ }
+
+ async getPurchasesByUrlAndOrderId(
+ merchantBaseUrl: string,
+ orderId: string,
+ ): Promise<WalletPurchase[]> {
+ const tx = this.tx;
+ return await tx.purchases.indexes.byUrlAndOrderId.getAll([
+ merchantBaseUrl,
+ orderId,
+ ]);
+ }
+
+ async getPurchasesByFulfillmentUrl(
+ fulfillmentUrl: string,
+ ): Promise<WalletPurchase[]> {
+ const tx = this.tx;
+ return await tx.purchases.indexes.byFulfillmentUrl.getAll(fulfillmentUrl);
+ }
+
+ async getPurchasesByExchange(
+ exchangeBaseUrl: string,
+ ): Promise<WalletPurchase[]> {
+ const tx = this.tx;
+ return await tx.purchases.indexes.byExchange.getAll(exchangeBaseUrl);
+ }
+
+ async getRefundGroup(
+ refundGroupId: string,
+ ): Promise<WalletRefundGroup | undefined> {
+ const tx = this.tx;
+ return await tx.refundGroups.get(refundGroupId);
+ }
+
+ async upsertRefundGroup(rec: WalletRefundGroup): Promise<void> {
+ const tx = this.tx;
+ await tx.refundGroups.put(rec);
+ }
+
+ async deleteRefundGroup(refundGroupId: string): Promise<void> {
+ const tx = this.tx;
+ await tx.refundGroups.delete(refundGroupId);
+ }
+
+ async getRefundGroupsByProposal(
+ proposalId: string,
+ ): Promise<WalletRefundGroup[]> {
+ const tx = this.tx;
+ return await tx.refundGroups.indexes.byProposalId.getAll(proposalId);
+ }
+
+ async getRefundItemsByGroup(
+ refundGroupId: string,
+ ): Promise<WalletRefundItem[]> {
+ const tx = this.tx;
+ // byRefundGroupId has an array keyPath (["refundGroupId"]), so its keys
+ // are single-element arrays and a bare string matches nothing.
+ return await tx.refundItems.indexes.byRefundGroupId.getAll([refundGroupId]);
+ }
+
+ async upsertRefundItem(rec: WalletRefundItem): Promise<number> {
+ const tx = this.tx;
+ const res = await tx.refundItems.put(rec);
+ checkDbInvariant(
+ typeof res.key === "number",
+ "refund item row id must be a number",
+ );
+ return res.key;
+ }
+
+ async deleteRefundItem(id: number): Promise<void> {
+ const tx = this.tx;
+ await tx.refundItems.delete(id);
+ }
+
+ async getRefundItemByCoinAndRtxid(
+ coinPub: string,
+ rtxid: number,
+ ): Promise<WalletRefundItem | undefined> {
+ const tx = this.tx;
+ return await tx.refundItems.indexes.byCoinPubAndRtxid.get([coinPub, rtxid]);
+ }
+
+ async upsertTombstone(rec: WalletTombstone): Promise<void> {
+ const tx = this.tx;
+ await tx.tombstones.put(rec);
+ }
+
async getDonationSummary(
donauBaseUrl: string,
year: number,
@@ -1005,7 +1115,7 @@ export class IdbWalletTransaction implements WalletDbTransaction {
);
}
- async getActivePurchases(): Promise<PurchaseRecord[]> {
+ async getActivePurchases(): Promise<WalletPurchase[]> {
return await this.tx.purchases.indexes.byStatus.getAll(getActiveKeyRange());
}
diff --git a/packages/taler-wallet-core/src/dbtx.ts b/packages/taler-wallet-core/src/dbtx.ts
@@ -69,11 +69,14 @@ import {
WalletDonationReceipt,
WalletDonationPlanchet,
DonationReceiptStatus,
+ WalletPurchase,
+ WalletRefundGroup,
+ WalletRefundItem,
+ WalletTombstone,
} from "./db-common.js";
import type {
ExchangeEntryRecord,
ExchangeDetailsRecord,
- PurchaseRecord,
} from "./db-indexeddb.js";
export interface GetCurrencyInfoDbResult {
@@ -137,7 +140,7 @@ export interface WalletDbTransaction {
upsertMailboxConfiguration(mailboxConf: MailboxConfiguration): Promise<void>;
- getPurchase(proposalId: string): Promise<PurchaseRecord | undefined>;
+ getPurchase(proposalId: string): Promise<WalletPurchase | undefined>;
/**
* Create or update the transaction metadata for a transaction.
@@ -181,6 +184,52 @@ export interface WalletDbTransaction {
*/
upsertContractTerms(rec: WalletContractTerms): Promise<void>;
+ upsertPurchase(rec: WalletPurchase): Promise<void>;
+
+ deletePurchase(proposalId: string): Promise<void>;
+
+ getPurchaseByUrlAndOrderId(
+ merchantBaseUrl: string,
+ orderId: string,
+ ): Promise<WalletPurchase | undefined>;
+
+ getPurchasesByUrlAndOrderId(
+ merchantBaseUrl: string,
+ orderId: string,
+ ): Promise<WalletPurchase[]>;
+
+ getPurchasesByFulfillmentUrl(
+ fulfillmentUrl: string,
+ ): Promise<WalletPurchase[]>;
+
+ getPurchasesByExchange(exchangeBaseUrl: string): Promise<WalletPurchase[]>;
+
+ getRefundGroup(refundGroupId: string): Promise<WalletRefundGroup | undefined>;
+
+ upsertRefundGroup(rec: WalletRefundGroup): Promise<void>;
+
+ deleteRefundGroup(refundGroupId: string): Promise<void>;
+
+ getRefundGroupsByProposal(proposalId: string): Promise<WalletRefundGroup[]>;
+
+ getRefundItemsByGroup(refundGroupId: string): Promise<WalletRefundItem[]>;
+
+ /**
+ * Create or update a refund item, returning its row id.
+ *
+ * The refundItems store is auto-incrementing on id.
+ */
+ upsertRefundItem(rec: WalletRefundItem): Promise<number>;
+
+ deleteRefundItem(id: number): Promise<void>;
+
+ getRefundItemByCoinAndRtxid(
+ coinPub: string,
+ rtxid: number,
+ ): Promise<WalletRefundItem | undefined>;
+
+ upsertTombstone(rec: WalletTombstone): Promise<void>;
+
getDonationSummary(
donauBaseUrl: string,
year: number,
@@ -480,7 +529,7 @@ export interface WalletDbTransaction {
getActivePeerPullDebits(): Promise<WalletPeerPullDebit[]>;
- getActivePurchases(): Promise<PurchaseRecord[]>;
+ getActivePurchases(): Promise<WalletPurchase[]>;
getCoinsByPubs(coinPubs: string[]): Promise<WalletCoin[]>;
diff --git a/packages/taler-wallet-core/src/dev-experiments.ts b/packages/taler-wallet-core/src/dev-experiments.ts
@@ -362,7 +362,7 @@ export async function applyDevExperiment(
}
rec.exchanges = [...exchangeSet];
rec.exchanges.sort();
- await tx.purchases.put(rec);
+ await tx.wtx.upsertPurchase(rec);
}
});
await rematerializeTransactions(wex, tx);
@@ -666,7 +666,7 @@ async function addFakeTx(
contractTermsRaw: ct,
h: contractTermsHash,
});
- await tx.purchases.put({
+ await tx.wtx.upsertPurchase({
autoRefundDeadline: undefined,
claimToken: encodeCrock(getRandomBytes(32)),
downloadSessionId: encodeCrock(getRandomBytes(32)),
diff --git a/packages/taler-wallet-core/src/donau.ts b/packages/taler-wallet-core/src/donau.ts
@@ -391,7 +391,7 @@ export async function generateDonauPlanchets(
proposalId: string,
): Promise<void> {
const res = await wex.runLegacyWalletDbTx(async (tx) => {
- const rec = await tx.purchases.get(proposalId);
+ const rec = await tx.wtx.getPurchase(proposalId);
if (!rec) {
return undefined;
}
@@ -516,7 +516,7 @@ export async function generateDonauPlanchets(
logger.trace(`donau planchets: ${j2s(donauPlanchets)}`);
await wex.runLegacyWalletDbTx(async (tx) => {
- const rec = await tx.purchases.get(proposalId);
+ const rec = await tx.wtx.getPurchase(proposalId);
if (!rec) {
return undefined;
}
diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts
@@ -3290,9 +3290,9 @@ async function purgeExchange(
// Remove from purchases, refundGroups, refundItems
{
const purchases =
- await tx.purchases.indexes.byExchange.getAll(exchangeBaseUrl);
+ await tx.wtx.getPurchasesByExchange(exchangeBaseUrl);
for (const purch of purchases) {
- const refunds = await tx.refundGroups.indexes.byProposalId.getAll(
+ const refunds = await tx.wtx.getRefundGroupsByProposal(
purch.proposalId,
);
for (const r of refunds) {
diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts
@@ -154,11 +154,11 @@ import {
WalletCoin,
WalletCoinSelection,
WalletDonationPlanchet,
+ WalletPurchase,
+ WalletRefundGroup,
+ WalletRefundItem,
} from "./db-common.js";
import {
- PurchaseRecord,
- RefundGroupRecord,
- RefundItemRecord,
RefundReason,
SlateRecord,
TokenRecord,
@@ -229,7 +229,7 @@ export class PayMerchantTransactionContext implements TransactionContext {
* Must be called each time the DB record for the transaction is updated.
*/
async updateTransactionMeta(tx: LegacyWalletTxHandle): Promise<void> {
- const purchaseRec = await tx.purchases.get(this.proposalId);
+ const purchaseRec = await tx.wtx.getPurchase(this.proposalId);
if (!purchaseRec) {
await tx.wtx.deleteTransactionMeta(this.transactionId);
return;
@@ -254,7 +254,7 @@ export class PayMerchantTransactionContext implements TransactionContext {
req?: LookupFullTransactionOpts,
): Promise<Transaction | undefined> {
const proposalId = this.proposalId;
- const purchaseRec = await tx.purchases.get(proposalId);
+ const purchaseRec = await tx.wtx.getPurchase(proposalId);
if (!purchaseRec) {
throw Error("not found");
}
@@ -301,7 +301,7 @@ export class PayMerchantTransactionContext implements TransactionContext {
);
const contractData = download.contractTerms;
- const refundsInfo = await tx.refundGroups.indexes.byProposalId.getAll(
+ const refundsInfo = await tx.wtx.getRefundGroupsByProposal(
purchaseRec.proposalId,
);
@@ -425,7 +425,7 @@ export class PayMerchantTransactionContext implements TransactionContext {
if (!rec) {
return;
}
- let relatedTransactions: PurchaseRecord[] = [];
+ let relatedTransactions: WalletPurchase[] = [];
// Automatically delete transactions that are a repurchase of this transaction,
// as they're typically hidden.
if (
@@ -434,7 +434,7 @@ export class PayMerchantTransactionContext implements TransactionContext {
rec.purchaseStatus !== PurchaseStatus.DoneRepurchaseDetected
) {
const otherTransactions =
- await tx.purchases.indexes.byFulfillmentUrl.getAll(
+ await tx.wtx.getPurchasesByFulfillmentUrl(
rec.download.fulfillmentUrl,
);
for (const otx of otherTransactions) {
@@ -568,15 +568,15 @@ export class PayMerchantTransactionContext implements TransactionContext {
async getRecordHandle(
tx: LegacyWalletTxHandle,
- ): Promise<[PurchaseRecord | undefined, RecordHandle<PurchaseRecord>]> {
- return getGenericRecordHandle<PurchaseRecord>(
+ ): Promise<[WalletPurchase | undefined, RecordHandle<WalletPurchase>]> {
+ return getGenericRecordHandle<WalletPurchase>(
this,
tx.wtx,
- async () => tx.purchases.get(this.proposalId),
+ async () => tx.wtx.getPurchase(this.proposalId),
async (r) => {
- await tx.purchases.put(r);
+ await tx.wtx.upsertPurchase(r);
},
- async () => tx.purchases.delete(this.proposalId),
+ async () => tx.wtx.deletePurchase(this.proposalId),
(r) => computePayMerchantTransactionState(r),
(r) => r.purchaseStatus,
() => this.updateTransactionMeta(tx),
@@ -586,7 +586,7 @@ export class PayMerchantTransactionContext implements TransactionContext {
async function computePayMerchantExchangesInTx(
tx: LegacyWalletTxHandle,
- purchaseRecord: PurchaseRecord,
+ purchaseRecord: WalletPurchase,
): Promise<string[]> {
if (purchaseRecord?.exchanges) {
return purchaseRecord.exchanges;
@@ -606,7 +606,7 @@ async function computePayMerchantExchangesInTx(
async function computePayMerchantTransactionScopesInTx(
tx: LegacyWalletTxHandle,
- purchaseRec: PurchaseRecord,
+ purchaseRec: WalletPurchase,
): Promise<ScopeInfo[]> {
if (purchaseRec.exchanges && purchaseRec.exchanges.length > 0) {
return await getScopeForAllExchanges(tx, purchaseRec.exchanges);
@@ -657,12 +657,12 @@ export class RefundTransactionContext implements TransactionContext {
* Must be called each time the DB record for the transaction is updated.
*/
async updateTransactionMeta(tx: LegacyWalletTxHandle): Promise<void> {
- const refundRec = await tx.refundGroups.get(this.refundGroupId);
+ const refundRec = await tx.wtx.getRefundGroup(this.refundGroupId);
if (!refundRec) {
await tx.wtx.deleteTransactionMeta(this.transactionId);
return;
}
- const purchaseRecord = await tx.purchases.get(refundRec.proposalId);
+ const purchaseRecord = await tx.wtx.getPurchase(refundRec.proposalId);
let exchanges: string[] = [];
if (purchaseRecord) {
exchanges = await computePayMerchantExchangesInTx(tx, purchaseRecord);
@@ -679,7 +679,7 @@ export class RefundTransactionContext implements TransactionContext {
async lookupFullTransaction(
tx: LegacyWalletTxHandle,
): Promise<Transaction | undefined> {
- const refundRecord = await tx.refundGroups.get(this.refundGroupId);
+ const refundRecord = await tx.wtx.getRefundGroup(this.refundGroupId);
if (!refundRecord) {
throw Error("not found");
}
@@ -697,7 +697,7 @@ export class RefundTransactionContext implements TransactionContext {
summary_i18n: maybeContractData.contractTerms.summary_i18n,
};
}
- const purchaseRecord = await tx.purchases.get(refundRecord.proposalId);
+ const purchaseRecord = await tx.wtx.getPurchase(refundRecord.proposalId);
let scopes: ScopeInfo[];
if (purchaseRecord) {
@@ -753,19 +753,17 @@ export class RefundTransactionContext implements TransactionContext {
tx: LegacyWalletTxHandle,
): Promise<{ notifs: WalletNotification[] }> {
const notifs: WalletNotification[] = [];
- const refundRecord = await tx.refundGroups.get(this.refundGroupId);
+ const refundRecord = await tx.wtx.getRefundGroup(this.refundGroupId);
if (!refundRecord) {
return { notifs };
}
- await tx.refundGroups.delete(this.refundGroupId);
+ await tx.wtx.deleteRefundGroup(this.refundGroupId);
await this.updateTransactionMeta(tx);
- await tx.tombstones.put({ id: this.transactionId });
- const items = await tx.refundItems.indexes.byRefundGroupId.getAll([
- refundRecord.refundGroupId,
- ]);
+ await tx.wtx.upsertTombstone({ id: this.transactionId });
+ const items = await tx.wtx.getRefundItemsByGroup(refundRecord.refundGroupId);
for (const item of items) {
if (item.id != null) {
- await tx.refundItems.delete(item.id);
+ await tx.wtx.deleteRefundItem(item.id);
}
}
return { notifs };
@@ -793,7 +791,7 @@ async function lookupMaybeContractData(
proposalId: string,
): Promise<DownloadedContractData | undefined> {
let contractData: DownloadedContractData | undefined = undefined;
- const purchaseTx = await tx.purchases.get(proposalId);
+ const purchaseTx = await tx.wtx.getPurchase(proposalId);
if (purchaseTx && purchaseTx.download) {
const download = purchaseTx.download;
const contractTermsRecord = await tx.wtx.getContractTerms(
@@ -879,7 +877,7 @@ async function failProposalClaimPermanently(
});
}
-function getPayRequestTimeout(purchase: PurchaseRecord): Duration {
+function getPayRequestTimeout(purchase: WalletPurchase): Duration {
return Duration.multiply(
{ d_ms: 15000 },
1 + (purchase.payInfo?.payCoinSelection?.coinPubs.length ?? 0) / 5,
@@ -891,7 +889,7 @@ export async function expectProposalDownloadByIdInTx(
tx: LegacyWalletTxHandle,
proposalId: string,
): Promise<DownloadedContractData> {
- const rec = await tx.purchases.get(proposalId);
+ const rec = await tx.wtx.getPurchase(proposalId);
if (!rec) {
throw Error("purchase record not found");
}
@@ -901,7 +899,7 @@ export async function expectProposalDownloadByIdInTx(
export async function expectProposalDownloadInTx(
wex: WalletExecutionContext,
tx: WalletDbTransaction,
- p: PurchaseRecord,
+ p: WalletPurchase,
): Promise<DownloadedContractData> {
if (!p.download) {
throw Error("expected proposal to be downloaded");
@@ -929,7 +927,7 @@ export async function expectProposalDownloadInTx(
*/
async function expectProposalDownload(
wex: WalletExecutionContext,
- p: PurchaseRecord,
+ p: WalletPurchase,
): Promise<DownloadedContractData> {
return await wex.runWalletDbTx(async (tx) => {
return expectProposalDownloadInTx(wex, tx, p);
@@ -941,7 +939,7 @@ async function processDownloadProposal(
proposalId: string,
): Promise<TaskRunResult> {
const proposal = await wex.runLegacyWalletDbTx(async (tx) => {
- return await tx.purchases.get(proposalId);
+ return await tx.wtx.getPurchase(proposalId);
});
if (!proposal) {
@@ -1196,9 +1194,13 @@ async function processDownloadProposal(
fulfillmentUrl &&
(fulfillmentUrl.startsWith("http://") ||
fulfillmentUrl.startsWith("https://"));
- let repurchase: PurchaseRecord | undefined = undefined;
- const otherPurchases =
- await tx.purchases.indexes.byFulfillmentUrl.getAll(fulfillmentUrl);
+ let repurchase: WalletPurchase | undefined = undefined;
+ // Only consumed under isResourceFulfillmentUrl, which implies
+ // fulfillmentUrl is set. Previously this passed undefined straight to
+ // the index, which scans the whole store for a result that is then unused.
+ const otherPurchases = fulfillmentUrl
+ ? await tx.wtx.getPurchasesByFulfillmentUrl(fulfillmentUrl)
+ : [];
if (isResourceFulfillmentUrl) {
for (const otherPurchase of otherPurchases) {
if (
@@ -1253,7 +1255,7 @@ async function startPayReplay(
async function generateSlate(
wex: WalletExecutionContext,
- purchase: PurchaseRecord,
+ purchase: WalletPurchase,
contractData: MerchantContractTermsV1,
contractTermsRaw: any,
choiceIndex: number,
@@ -1354,10 +1356,7 @@ async function createOrReusePurchase(
// Find existing proposals from the same merchant
// with the same order ID.
const oldProposals = await wex.runLegacyWalletDbTx(async (tx) => {
- return tx.purchases.indexes.byUrlAndOrderId.getAll([
- merchantBaseUrl,
- orderId,
- ]);
+ return tx.wtx.getPurchasesByUrlAndOrderId(merchantBaseUrl, orderId);
});
if (oldProposals.length > 1) {
@@ -1463,7 +1462,7 @@ async function createOrReusePurchase(
const secretSeed = encodeCrock(getRandomBytes(32));
- const proposalRecord: PurchaseRecord = {
+ const proposalRecord: WalletPurchase = {
download: undefined,
noncePriv: priv,
noncePub: pub,
@@ -1493,7 +1492,7 @@ async function createOrReusePurchase(
const ctx = new PayMerchantTransactionContext(wex, proposalId);
await wex.runLegacyWalletDbTx(async (tx) => {
- await tx.purchases.put(proposalRecord);
+ await tx.wtx.upsertPurchase(proposalRecord);
await ctx.updateTransactionMeta(tx);
const oldTxState: TransactionState = {
major: TransactionMajorState.None,
@@ -1600,7 +1599,7 @@ async function storePayReplaySuccess(
});
}
-function setCoinSel(rec: PurchaseRecord, coinSel: PayCoinSelection): void {
+function setCoinSel(rec: WalletPurchase, coinSel: PayCoinSelection): void {
checkLogicInvariant(!!rec.payInfo);
rec.payInfo.payCoinSelection = {
coinContributions: coinSel.coins.map((x) => x.contribution),
@@ -1616,7 +1615,7 @@ async function reselectCoinsTx(
ctx: PayMerchantTransactionContext,
excludeCoinPub?: string,
): Promise<void> {
- const p = await tx.purchases.get(ctx.proposalId);
+ const p = await tx.wtx.getPurchase(ctx.proposalId);
if (!p) {
return;
}
@@ -1717,7 +1716,7 @@ async function reselectCoinsTx(
};
}
- await tx.purchases.put(p);
+ await tx.wtx.upsertPurchase(p);
await ctx.updateTransactionMeta(tx);
if (p.payInfo.payCoinSelection) {
@@ -1757,7 +1756,7 @@ async function handleInsufficientFunds(
const ctx = new PayMerchantTransactionContext(wex, proposalId);
const proposal = await wex.runLegacyWalletDbTx(async (tx) => {
- return tx.purchases.get(proposalId);
+ return tx.wtx.getPurchase(proposalId);
});
if (!proposal) {
return TaskRunResult.finished();
@@ -1844,14 +1843,14 @@ async function lookupProposalOrRepurchase(
): Promise<
| {
proposalId: string;
- purchaseRec: PurchaseRecord;
+ purchaseRec: WalletPurchase;
contractTerms: MerchantContractTerms;
contractTermsHash: string;
}
| undefined
> {
return await wex.runLegacyWalletDbTx(async (tx) => {
- let purchaseRec = await tx.purchases.get(proposalId);
+ let purchaseRec = await tx.wtx.getPurchase(proposalId);
if (!purchaseRec) {
return undefined;
@@ -1861,7 +1860,7 @@ async function lookupProposalOrRepurchase(
const existingProposalId = purchaseRec.repurchaseProposalId;
if (existingProposalId) {
logger.trace("using existing purchase for same product");
- const oldProposal = await tx.purchases.get(existingProposalId);
+ const oldProposal = await tx.wtx.getPurchase(existingProposalId);
if (oldProposal) {
purchaseRec = oldProposal;
}
@@ -2144,7 +2143,7 @@ async function checkPaymentByProposalId(
}
}
-function isPurchasePaid(purchase: PurchaseRecord): boolean {
+function isPurchasePaid(purchase: WalletPurchase): boolean {
return (
purchase.purchaseStatus === PurchaseStatus.Done ||
purchase.purchaseStatus === PurchaseStatus.PendingQueryingRefund ||
@@ -2249,7 +2248,7 @@ async function waitProposalDownloaded(
const { purchase, retryInfo } = await ctx.wex.runLegacyWalletDbTx(
async (tx) => {
return {
- purchase: await tx.purchases.get(ctx.proposalId),
+ purchase: await tx.wtx.getPurchase(ctx.proposalId),
retryInfo: await tx.wtx.getOperationRetry(ctx.taskId),
};
},
@@ -2382,7 +2381,7 @@ async function waitPaymentResult(
},
async checkState() {
const txRes = await ctx.wex.runLegacyWalletDbTx(async (tx) => {
- const purchase = await tx.purchases.get(ctx.proposalId);
+ const purchase = await tx.wtx.getPurchase(ctx.proposalId);
const retryRecord = await tx.wtx.getOperationRetry(ctx.taskId);
return { purchase, retryRecord };
});
@@ -2449,7 +2448,7 @@ export async function getChoicesForPayment(
}
const proposalId = parsedTx.proposalId;
const { proposal, d } = await wex.runLegacyWalletDbTx(async (tx) => {
- const proposal = await tx.purchases.get(proposalId);
+ const proposal = await tx.wtx.getPurchase(proposalId);
let d: DownloadedContractData | undefined = undefined;
if (proposal) {
const download = proposal.download;
@@ -2739,7 +2738,7 @@ export async function confirmPay(
`executing confirmPay with proposalId ${proposalId} and sessionIdOverride ${sessionIdOverride}`,
);
const proposal = await wex.runLegacyWalletDbTx(async (tx) => {
- return tx.purchases.get(proposalId);
+ return tx.wtx.getPurchase(proposalId);
});
if (!proposal) {
@@ -2752,7 +2751,7 @@ export async function confirmPay(
}
const existingPurchase = await wex.runLegacyWalletDbTx(async (tx) => {
- const purchase = await tx.purchases.get(proposalId);
+ const purchase = await tx.wtx.getPurchase(proposalId);
if (
purchase &&
sessionIdOverride !== undefined &&
@@ -2763,7 +2762,7 @@ export async function confirmPay(
if (purchase.purchaseStatus === PurchaseStatus.Done) {
purchase.purchaseStatus = PurchaseStatus.PendingPayingReplay;
}
- await tx.purchases.put(purchase);
+ await tx.wtx.upsertPurchase(purchase);
await ctx.updateTransactionMeta(tx);
}
return purchase;
@@ -3031,7 +3030,7 @@ export async function processPurchase(
proposalId: string,
): Promise<TaskRunResult> {
const purchase = await wex.runLegacyWalletDbTx(async (tx) => {
- return tx.purchases.get(proposalId);
+ return tx.wtx.getPurchase(proposalId);
});
if (!purchase) {
return {
@@ -3099,7 +3098,7 @@ async function processPurchasePay(
proposalId: string,
): Promise<TaskRunResult> {
const purchase = await wex.runLegacyWalletDbTx(async (tx) => {
- return tx.purchases.get(proposalId);
+ return tx.wtx.getPurchase(proposalId);
});
if (!purchase) {
return {
@@ -3206,7 +3205,7 @@ async function processPurchasePay(
);
const transitionDone = await wex.runLegacyWalletDbTx(async (tx) => {
- const p = await tx.purchases.get(proposalId);
+ const p = await tx.wtx.getPurchase(proposalId);
if (!p) {
return false;
}
@@ -3228,7 +3227,7 @@ async function processPurchasePay(
};
p.payInfo.payCoinSelectionUid = encodeCrock(getRandomBytes(16));
p.purchaseStatus = PurchaseStatus.PendingPaying;
- await tx.purchases.put(p);
+ await tx.wtx.upsertPurchase(p);
await ctx.updateTransactionMeta(tx);
await spendCoins(wex, tx, {
transactionId: ctx.transactionId,
@@ -3495,7 +3494,7 @@ async function processPurchasePay(
return;
}
purchase.payInfo.slateTokenSigs = tokenSigs;
- tx.purchases.put(purchase);
+ tx.wtx.upsertPurchase(purchase);
});
}
@@ -3753,7 +3752,7 @@ const transitionResume: {
};
export function computePayMerchantTransactionState(
- purchaseRecord: PurchaseRecord,
+ purchaseRecord: WalletPurchase,
): TransactionState {
switch (purchaseRecord.purchaseStatus) {
// Pending States
@@ -3910,7 +3909,7 @@ export function computePayMerchantTransactionState(
}
export function computePayMerchantTransactionActions(
- purchaseRecord: PurchaseRecord,
+ purchaseRecord: WalletPurchase,
): TransactionAction[] {
switch (purchaseRecord.purchaseStatus) {
// Pending States
@@ -4026,10 +4025,7 @@ export async function sharePayment(
): Promise<SharePaymentResult> {
// First, translate the order ID into a proposal ID
const proposalId = await wex.runLegacyWalletDbTx(async (tx) => {
- const p = await tx.purchases.indexes.byUrlAndOrderId.get([
- merchantBaseUrl,
- orderId,
- ]);
+ const p = await tx.wtx.getPurchaseByUrlAndOrderId(merchantBaseUrl, orderId);
return p?.proposalId;
});
@@ -4118,12 +4114,12 @@ async function checkIfOrderIsAlreadyPaid(
async function processPurchaseDialogProposed(
wex: WalletExecutionContext,
- purchase: PurchaseRecord,
+ purchase: WalletPurchase,
): Promise<TaskRunResult> {
const proposalId = purchase.proposalId;
const ctx = new PayMerchantTransactionContext(wex, proposalId);
const txRes = await wex.runLegacyWalletDbTx(async (tx) => {
- const rec = await tx.purchases.get(proposalId);
+ const rec = await tx.wtx.getPurchase(proposalId);
if (!rec) {
return undefined;
}
@@ -4165,13 +4161,13 @@ async function processPurchaseDialogProposed(
*/
async function processPurchaseDialogShared(
wex: WalletExecutionContext,
- purchase: PurchaseRecord,
+ purchase: WalletPurchase,
): Promise<TaskRunResult> {
const proposalId = purchase.proposalId;
logger.trace(`processing dialog-shared for proposal ${proposalId}`);
const ctx = new PayMerchantTransactionContext(wex, proposalId);
const txRes = await wex.runLegacyWalletDbTx(async (tx) => {
- const rec = await tx.purchases.get(proposalId);
+ const rec = await tx.wtx.getPurchase(proposalId);
if (!rec) {
return undefined;
}
@@ -4241,7 +4237,7 @@ async function processPurchaseDialogShared(
async function processPurchaseAutoRefund(
wex: WalletExecutionContext,
- purchase: PurchaseRecord,
+ purchase: WalletPurchase,
): Promise<TaskRunResult> {
const proposalId = purchase.proposalId;
const ctx = new PayMerchantTransactionContext(wex, proposalId);
@@ -4266,7 +4262,7 @@ async function processPurchaseAutoRefund(
);
const totalKnownRefund = await wex.runLegacyWalletDbTx(async (tx) => {
- const refunds = await tx.refundGroups.indexes.byProposalId.getAll(
+ const refunds = await tx.wtx.getRefundGroupsByProposal(
purchase.proposalId,
);
const am = Amounts.parseOrThrow(amountRaw);
@@ -4341,7 +4337,7 @@ async function processPurchaseAutoRefund(
async function processPurchaseAbortingRefund(
wex: WalletExecutionContext,
- purchase: PurchaseRecord,
+ purchase: WalletPurchase,
): Promise<TaskRunResult> {
const proposalId = purchase.proposalId;
const ctx = new PayMerchantTransactionContext(wex, proposalId);
@@ -4479,7 +4475,7 @@ async function processPurchaseAbortingRefund(
async function processPurchaseQueryRefund(
wex: WalletExecutionContext,
- purchase: PurchaseRecord,
+ purchase: WalletPurchase,
): Promise<TaskRunResult> {
const proposalId = purchase.proposalId;
logger.trace(`processing query-refund for proposal ${proposalId}`);
@@ -4531,7 +4527,7 @@ async function processPurchaseQueryRefund(
async function processPurchaseAcceptRefund(
wex: WalletExecutionContext,
- purchase: PurchaseRecord,
+ purchase: WalletPurchase,
): Promise<TaskRunResult> {
const download = await expectProposalDownload(wex, purchase);
@@ -4573,10 +4569,7 @@ export async function startRefundQueryForUri(
throw Error("expected taler://refund URI");
}
const purchaseRecord = await wex.runLegacyWalletDbTx(async (tx) => {
- return tx.purchases.indexes.byUrlAndOrderId.get([
- parsedUri.merchantBaseUrl,
- parsedUri.orderId,
- ]);
+ return tx.wtx.getPurchaseByUrlAndOrderId(parsedUri.merchantBaseUrl, parsedUri.orderId);
});
if (!purchaseRecord) {
logger.error(
@@ -4618,7 +4611,7 @@ export async function startQueryRefund(
async function computeRefreshRequest(
wex: WalletExecutionContext,
tx: LegacyWalletTxHandle,
- items: RefundItemRecord[],
+ items: WalletRefundItem[],
): Promise<CoinRefreshRequest[]> {
const refreshCoins: CoinRefreshRequest[] = [];
for (const item of items) {
@@ -4669,7 +4662,7 @@ function getItemStatus(rf: MerchantCoinRefundStatus): RefundItemStatus {
*/
async function storeRefunds(
wex: WalletExecutionContext,
- purchase: PurchaseRecord,
+ purchase: WalletPurchase,
refunds: MerchantCoinRefundStatus[],
reason: RefundReason,
): Promise<TaskRunResult> {
@@ -4710,16 +4703,13 @@ async function storeRefunds(
return;
}
- let newGroup: RefundGroupRecord | undefined = undefined;
+ let newGroup: WalletRefundGroup | undefined = undefined;
// Pending, but not part of an aborted refund group.
let numPendingItemsTotal = 0;
- const newGroupRefunds: RefundItemRecord[] = [];
+ const newGroupRefunds: WalletRefundItem[] = [];
for (const rf of refunds) {
- const oldItem = await tx.refundItems.indexes.byCoinPubAndRtxid.get([
- rf.coin_pub,
- rf.rtransaction_id,
- ]);
+ const oldItem = await tx.wtx.getRefundItemByCoinAndRtxid(rf.coin_pub, rf.rtransaction_id);
if (oldItem) {
logger.info("already have refund in database");
if (oldItem.status === RefundItemStatus.Done) {
@@ -4735,7 +4725,7 @@ async function storeRefunds(
oldItem.status = RefundItemStatus.Failed;
}
}
- await tx.refundItems.put(oldItem);
+ await tx.wtx.upsertRefundItem(oldItem);
} else {
// Put refund item into a new group!
if (!newGroup) {
@@ -4751,7 +4741,7 @@ async function storeRefunds(
};
}
const status: RefundItemStatus = getItemStatus(rf);
- const newItem: RefundItemRecord = {
+ const newItem: WalletRefundItem = {
coinPub: rf.coin_pub,
executionTime: timestampProtocolToDb(rf.execution_time),
obtainedTime: timestampPreciseToDb(now),
@@ -4764,7 +4754,7 @@ async function storeRefunds(
numPendingItemsTotal += 1;
}
newGroupRefunds.push(newItem);
- await tx.refundItems.put(newItem);
+ await tx.wtx.upsertRefundItem(newItem);
}
}
@@ -4793,7 +4783,7 @@ async function storeRefunds(
wex,
newGroup.refundGroupId,
);
- await tx.refundGroups.put(newGroup);
+ await tx.wtx.upsertRefundGroup(newGroup);
await refundCtx.updateTransactionMeta(tx);
applyNotifyTransition(tx.notify, refundCtx.transactionId, {
oldTxState: { major: TransactionMajorState.None },
@@ -4804,7 +4794,7 @@ async function storeRefunds(
});
}
- const refundGroups = await tx.refundGroups.indexes.byProposalId.getAll(
+ const refundGroups = await tx.wtx.getRefundGroupsByProposal(
myPurchase.proposalId,
);
@@ -4824,9 +4814,7 @@ async function storeRefunds(
default:
assertUnreachable(refundGroup.status);
}
- const items = await tx.refundItems.indexes.byRefundGroupId.getAll([
- refundGroup.refundGroupId,
- ]);
+ const items = await tx.wtx.getRefundItemsByGroup(refundGroup.refundGroupId);
let numPending = 0;
let numFailed = 0;
for (const item of items) {
@@ -4847,7 +4835,7 @@ async function storeRefunds(
} else {
refundGroup.status = RefundGroupStatus.Failed;
}
- await tx.refundGroups.put(refundGroup);
+ await tx.wtx.upsertRefundGroup(refundGroup);
await refundCtx.updateTransactionMeta(tx);
const refreshCoins = await computeRefreshRequest(wex, tx, items);
const newTxState: TransactionState =
@@ -4912,7 +4900,7 @@ async function storeRefunds(
}
export function computeRefundTransactionState(
- refundGroupRecord: RefundGroupRecord,
+ refundGroupRecord: WalletRefundGroup,
): TransactionState {
switch (refundGroupRecord.status) {
case RefundGroupStatus.Aborted: