From 472899f066ce29b86bdc6b02a621f755a7c3b260 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 10 Jun 2024 16:04:18 +0200 Subject: wallet-core: introduce finalizing state --- packages/taler-util/src/transactions-types.ts | 5 ++- packages/taler-wallet-core/src/balance.ts | 8 ++--- packages/taler-wallet-core/src/db.ts | 12 +++++-- packages/taler-wallet-core/src/pay-merchant.ts | 45 +++++++++++++++++++++++--- packages/taler-wallet-core/src/shepherd.ts | 8 ++--- packages/taler-wallet-core/src/transactions.ts | 40 +++++++++++------------ packages/taler-wallet-core/src/versions.ts | 2 +- 7 files changed, 83 insertions(+), 37 deletions(-) diff --git a/packages/taler-util/src/transactions-types.ts b/packages/taler-util/src/transactions-types.ts index db2133944..a6ac5aec6 100644 --- a/packages/taler-util/src/transactions-types.ts +++ b/packages/taler-util/src/transactions-types.ts @@ -105,8 +105,11 @@ export enum TransactionMajorState { Done = "done", Aborting = "aborting", Aborted = "aborted", - Suspended = "suspended", Dialog = "dialog", + Finalizing = "finalizing", + // Plain suspended is always a suspended pending state. + Suspended = "suspended", + SuspendedFinalizing = "suspended-finalizing", SuspendedAborting = "suspended-aborting", Failed = "failed", Expired = "expired", diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts index 4f06e3756..381028906 100644 --- a/packages/taler-wallet-core/src/balance.ts +++ b/packages/taler-wallet-core/src/balance.ts @@ -69,8 +69,8 @@ import { ExchangeRestrictionSpec, findMatchingWire } from "./coinSelection.js"; import { DepositOperationStatus, ExchangeEntryDbRecordStatus, - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, PeerPushDebitStatus, RefreshGroupRecord, RefreshOperationStatus, @@ -304,8 +304,8 @@ export async function getBalancesInsideTransaction( const balanceStore: BalancesStore = new BalancesStore(wex, tx); const keyRangeActive = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); await tx.exchanges.iter().forEachAsync(async (ex) => { diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 6bf212c6f..5c381eea7 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -248,6 +248,9 @@ export function timestampOptionalAbsoluteFromDb( * 0x0103_nnnn: aborting * 0x0110_nnnn: suspended * 0x0113_nnnn: suspended-aborting + * a=2: finalizing + * 0x0200_nnnn: finalizing + * 0x0210_nnnn: suspended-finalizing * a=5: final * 0x0500_nnnn: done * 0x0501_nnnn: failed @@ -260,12 +263,12 @@ export function timestampOptionalAbsoluteFromDb( /** * First possible operation status in the active range (inclusive). */ -export const OPERATION_STATUS_ACTIVE_FIRST = 0x0100_0000; +export const OPERATION_STATUS_NONFINAL_FIRST = 0x0100_0000; /** * LAST possible operation status in the active range (inclusive). */ -export const OPERATION_STATUS_ACTIVE_LAST = 0x0113_ffff; +export const OPERATION_STATUS_NONFINAL_LAST = 0x0210_ffff; /** * Status of a withdrawal. @@ -1094,10 +1097,15 @@ export enum PurchaseStatus { /** * Query for refund (until auto-refund deadline is reached). + * + * Legacy state for compatibility. */ PendingQueryingAutoRefund = 0x0100_0004, SuspendedQueryingAutoRefund = 0x0110_0004, + FinalizingQueryingAutoRefund = 0x0200_0001, + SuspendedFinalizingQueryingAutoRefund = 0x0210_0001, + PendingAcceptRefund = 0x0100_0005, SuspendedPendingAcceptRefund = 0x0110_0005, diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts index 91ea4bd1d..ee154252f 100644 --- a/packages/taler-wallet-core/src/pay-merchant.ts +++ b/packages/taler-wallet-core/src/pay-merchant.ts @@ -2093,6 +2093,7 @@ export async function processPurchase( case PurchaseStatus.PendingPayingReplay: return processPurchasePay(wex, proposalId); case PurchaseStatus.PendingQueryingRefund: + case PurchaseStatus.FinalizingQueryingAutoRefund: return processPurchaseQueryRefund(wex, purchase); case PurchaseStatus.PendingQueryingAutoRefund: return processPurchaseAutoRefund(wex, purchase); @@ -2117,6 +2118,7 @@ export async function processPurchase( case PurchaseStatus.SuspendedPendingAcceptRefund: case PurchaseStatus.SuspendedQueryingAutoRefund: case PurchaseStatus.SuspendedQueryingRefund: + case PurchaseStatus.SuspendedFinalizingQueryingAutoRefund: case PurchaseStatus.FailedAbort: case PurchaseStatus.FailedPaidByOther: return TaskRunResult.finished(); @@ -2494,6 +2496,9 @@ const transitionSuspend: { [PurchaseStatus.PendingQueryingAutoRefund]: { next: PurchaseStatus.SuspendedQueryingAutoRefund, }, + [PurchaseStatus.FinalizingQueryingAutoRefund]: { + next: PurchaseStatus.SuspendedFinalizingQueryingAutoRefund, + }, }; const transitionResume: { @@ -2516,6 +2521,9 @@ const transitionResume: { [PurchaseStatus.SuspendedQueryingAutoRefund]: { next: PurchaseStatus.PendingQueryingAutoRefund, }, + [PurchaseStatus.SuspendedFinalizingQueryingAutoRefund]: { + next: PurchaseStatus.FinalizingQueryingAutoRefund, + }, }; export function computePayMerchantTransactionState( @@ -2644,6 +2652,16 @@ export function computePayMerchantTransactionState( major: TransactionMajorState.Failed, minor: TransactionMinorState.PaidByOther, }; + case PurchaseStatus.FinalizingQueryingAutoRefund: + return { + major: TransactionMajorState.Finalizing, + minor: TransactionMinorState.AutoRefund, + }; + case PurchaseStatus.SuspendedFinalizingQueryingAutoRefund: + return { + major: TransactionMajorState.SuspendedFinalizing, + minor: TransactionMinorState.AutoRefund, + }; default: assertUnreachable(purchaseRecord.purchaseStatus); } @@ -2742,6 +2760,14 @@ export function computePayMerchantTransactionActions( return [TransactionAction.Delete]; case PurchaseStatus.FailedPaidByOther: return [TransactionAction.Delete]; + case PurchaseStatus.FinalizingQueryingAutoRefund: + return [ + TransactionAction.Suspend, + TransactionAction.Retry, + TransactionAction.Delete, + ]; + case PurchaseStatus.SuspendedFinalizingQueryingAutoRefund: + return [TransactionAction.Resume, TransactionAction.Delete]; default: assertUnreachable(purchaseRecord.purchaseStatus); } @@ -2944,8 +2970,12 @@ async function processPurchaseAutoRefund( logger.warn("purchase does not exist anymore"); return; } - if (p.purchaseStatus !== PurchaseStatus.PendingQueryingAutoRefund) { - return; + switch (p.purchaseStatus) { + case PurchaseStatus.PendingQueryingAutoRefund: + case PurchaseStatus.FinalizingQueryingAutoRefund: + break; + default: + return; } const oldTxState = computePayMerchantTransactionState(p); p.purchaseStatus = PurchaseStatus.Done; @@ -2991,8 +3021,12 @@ async function processPurchaseAutoRefund( logger.warn("purchase does not exist anymore"); return; } - if (p.purchaseStatus !== PurchaseStatus.PendingQueryingAutoRefund) { - return; + switch (p.purchaseStatus) { + case PurchaseStatus.PendingQueryingAutoRefund: + case PurchaseStatus.FinalizingQueryingAutoRefund: + break; + default: + return; } const oldTxState = computePayMerchantTransactionState(p); p.purchaseStatus = PurchaseStatus.PendingAcceptRefund; @@ -3536,7 +3570,8 @@ async function storeRefunds( if (isAborting) { myPurchase.purchaseStatus = PurchaseStatus.AbortedRefunded; } else if (shouldCheckAutoRefund) { - myPurchase.purchaseStatus = PurchaseStatus.PendingQueryingAutoRefund; + myPurchase.purchaseStatus = + PurchaseStatus.FinalizingQueryingAutoRefund; } else { myPurchase.purchaseStatus = PurchaseStatus.Done; } diff --git a/packages/taler-wallet-core/src/shepherd.ts b/packages/taler-wallet-core/src/shepherd.ts index 0f285eb39..470f45aff 100644 --- a/packages/taler-wallet-core/src/shepherd.ts +++ b/packages/taler-wallet-core/src/shepherd.ts @@ -50,8 +50,8 @@ import { parseTaskIdentifier, } from "./common.js"; import { - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, OperationRetryRecord, WalletDbAllStoresReadOnlyTransaction, WalletDbReadOnlyTransaction, @@ -1012,8 +1012,8 @@ export async function getActiveTaskIds( }, async (tx) => { const active = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); // Withdrawals diff --git a/packages/taler-wallet-core/src/transactions.ts b/packages/taler-wallet-core/src/transactions.ts index 0f7b1c3ca..7782d09ba 100644 --- a/packages/taler-wallet-core/src/transactions.ts +++ b/packages/taler-wallet-core/src/transactions.ts @@ -62,8 +62,8 @@ import { DenomLossEventRecord, DepositElementStatus, DepositGroupRecord, - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, OperationRetryRecord, PeerPullCreditRecord, PeerPullDebitRecordStatus, @@ -1968,8 +1968,8 @@ async function iterRecordsForWithdrawal( let withdrawalGroupRecords: WithdrawalGroupRecord[]; if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); withdrawalGroupRecords = await tx.withdrawalGroups.indexes.byStatus.getAll(keyRange); @@ -1990,8 +1990,8 @@ async function iterRecordsForDeposit( let dgs: DepositGroupRecord[]; if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); dgs = await tx.depositGroups.indexes.byStatus.getAll(keyRange); } else { @@ -2011,8 +2011,8 @@ async function iterRecordsForDenomLoss( let dgs: DenomLossEventRecord[]; if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); dgs = await tx.denomLossEvents.indexes.byStatus.getAll(keyRange); } else { @@ -2031,8 +2031,8 @@ async function iterRecordsForRefund( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); await tx.refundGroups.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -2047,8 +2047,8 @@ async function iterRecordsForPurchase( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); await tx.purchases.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -2063,8 +2063,8 @@ async function iterRecordsForPeerPullCredit( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); await tx.peerPullCredit.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -2079,8 +2079,8 @@ async function iterRecordsForPeerPullDebit( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); await tx.peerPullDebit.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -2095,8 +2095,8 @@ async function iterRecordsForPeerPushDebit( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); await tx.peerPushDebit.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -2111,8 +2111,8 @@ async function iterRecordsForPeerPushCredit( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - OPERATION_STATUS_ACTIVE_FIRST, - OPERATION_STATUS_ACTIVE_LAST, + OPERATION_STATUS_NONFINAL_FIRST, + OPERATION_STATUS_NONFINAL_LAST, ); await tx.peerPushCredit.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { diff --git a/packages/taler-wallet-core/src/versions.ts b/packages/taler-wallet-core/src/versions.ts index d33a23cdd..8c1ac5fc2 100644 --- a/packages/taler-wallet-core/src/versions.ts +++ b/packages/taler-wallet-core/src/versions.ts @@ -52,7 +52,7 @@ export const WALLET_BANK_CONVERSION_API_PROTOCOL_VERSION = "2:0:0"; /** * Libtool version of the wallet-core API. */ -export const WALLET_CORE_API_PROTOCOL_VERSION = "5:0:0"; +export const WALLET_CORE_API_PROTOCOL_VERSION = "7:0:0"; /** * Libtool rules: -- cgit v1.2.3