diff options
Diffstat (limited to 'packages')
12 files changed, 407 insertions, 55 deletions
| diff --git a/packages/taler-util/src/transactions-types.ts b/packages/taler-util/src/transactions-types.ts index c06bc7369..5f5b9d112 100644 --- a/packages/taler-util/src/transactions-types.ts +++ b/packages/taler-util/src/transactions-types.ts @@ -125,6 +125,15 @@ export enum TransactionMinorState {    AcceptRefund = "accept-refund",  } +export enum TransactionAction { +  Delete = "delete", +  Suspend = "suspend", +  Resume = "resume", +  Abort = "abort", +  Fail = "fail", +  Retry = "retry", +} +  export interface TransactionsResponse {    // a list of past and pending transactions sorted by pending, timestamp and transactionId.    // In case two events are both pending and have the same timestamp, @@ -150,6 +159,11 @@ export interface TransactionCommon {    txState: TransactionState;    /** +   * Possible transitions based on the current state. +   */ +  txActions: string[]; + +  /**     * Raw amount of the transaction (exclusive of fees or other extra costs).     */    amountRaw: AmountString; diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 3147cb9b9..74332de33 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -1131,7 +1131,7 @@ export enum PurchaseStatus {    /**     * Proposal downloaded, but the user needs to accept/reject it.     */ -  Proposed = 30, +  DialogProposed = 30,    /**     * The user has rejected the proposal. diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts index 0aca45551..23c6e787a 100644 --- a/packages/taler-wallet-core/src/operations/backup/export.ts +++ b/packages/taler-wallet-core/src/operations/backup/export.ts @@ -418,7 +418,7 @@ export async function exportBackup(              break;            case PurchaseStatus.PendingPayingReplay:            case PurchaseStatus.PendingDownloadingProposal: -          case PurchaseStatus.Proposed: +          case PurchaseStatus.DialogProposed:            case PurchaseStatus.PendingPaying:              propStatus = BackupProposalStatus.Proposed;              break; diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts index 5efdb78c1..d3346a3a2 100644 --- a/packages/taler-wallet-core/src/operations/backup/import.ts +++ b/packages/taler-wallet-core/src/operations/backup/import.ts @@ -578,7 +578,7 @@ export async function importBackup(              proposalStatus = PurchaseStatus.Done;              break;            case BackupProposalStatus.Proposed: -            proposalStatus = PurchaseStatus.Proposed; +            proposalStatus = PurchaseStatus.DialogProposed;              break;            case BackupProposalStatus.PermanentlyFailed:              proposalStatus = PurchaseStatus.AbortedIncompletePayment; diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index 1ed2a705e..6387fc9b7 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -59,11 +59,11 @@ import {    TransactionType,    URL,    WireFee, +  TransactionAction,  } from "@gnu-taler/taler-util";  import {    DenominationRecord,    DepositGroupRecord, -  OperationStatus,    DepositElementStatus,  } from "../db.js";  import { TalerError } from "@gnu-taler/taler-util"; @@ -115,6 +115,7 @@ export function computeDepositTransactionStatus(          major: TransactionMajorState.Done,        };      } +    // FIXME: We should actually use separate pending states for this!      case DepositOperationStatus.Pending: {        const numTotal = dg.payCoinSelection.coinPubs.length;        let numDeposited = 0; @@ -134,9 +135,6 @@ export function computeDepositTransactionStatus(          }        } -      logger.info(`num total ${numTotal}`); -      logger.info(`num deposited ${numDeposited}`); -        if (numKycRequired > 0) {          return {            major: TransactionMajorState.Pending, @@ -181,6 +179,57 @@ export function computeDepositTransactionStatus(    }  } +export function computeDepositTransactionActions( +  dg: DepositGroupRecord, +): TransactionAction[] { +  switch (dg.operationStatus) { +    case DepositOperationStatus.Finished: { +      return [TransactionAction.Delete]; +    } +    case DepositOperationStatus.Pending: { +      const numTotal = dg.payCoinSelection.coinPubs.length; +      let numDeposited = 0; +      let numKycRequired = 0; +      let numWired = 0; +      for (let i = 0; i < numTotal; i++) { +        if (dg.depositedPerCoin[i]) { +          numDeposited++; +        } +        switch (dg.transactionPerCoin[i]) { +          case DepositElementStatus.KycRequired: +            numKycRequired++; +            break; +          case DepositElementStatus.Wired: +            numWired++; +            break; +        } +      } + +      if (numKycRequired > 0) { +        return [TransactionAction.Suspend, TransactionAction.Fail]; +      } + +      if (numDeposited == numTotal) { +        return [TransactionAction.Suspend, TransactionAction.Fail]; +      } + +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    } +    case DepositOperationStatus.Suspended: +      return [TransactionAction.Resume]; +    case DepositOperationStatus.Aborting: +      return [TransactionAction.Fail, TransactionAction.Suspend]; +    case DepositOperationStatus.Aborted: +      return [TransactionAction.Delete]; +    case DepositOperationStatus.Failed: +      return [TransactionAction.Delete]; +    case DepositOperationStatus.SuspendedAborting: +      return [TransactionAction.Resume, TransactionAction.Fail]; +    default: +      throw Error(`unexpected deposit group state (${dg.operationStatus})`); +  } +} +  export async function suspendDepositGroup(    ws: InternalWalletState,    depositGroupId: string, @@ -309,7 +358,7 @@ export async function abortDepositGroup(    notifyTransition(ws, transactionId, transitionInfo);  } -export async function cancelAbortingDepositGroup( +export async function failDepositTransaction(    ws: InternalWalletState,    depositGroupId: string,  ): Promise<void> { diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts index 8462f2fb9..dce2a30ed 100644 --- a/packages/taler-wallet-core/src/operations/pay-merchant.ts +++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts @@ -70,6 +70,7 @@ import {    TalerProtocolTimestamp,    TalerProtocolViolationError,    TalerUriAction, +  TransactionAction,    TransactionMajorState,    TransactionMinorState,    TransactionState, @@ -547,7 +548,7 @@ async function processDownloadProposal(            await tx.purchases.put(p);          }        } else { -        p.purchaseStatus = PurchaseStatus.Proposed; +        p.purchaseStatus = PurchaseStatus.DialogProposed;          await tx.purchases.put(p);        }        const newTxState = computePayMerchantTransactionState(p); @@ -994,7 +995,7 @@ export async function checkPaymentByProposalId(        return tx.purchases.get(proposalId);      }); -  if (!purchase || purchase.purchaseStatus === PurchaseStatus.Proposed) { +  if (!purchase || purchase.purchaseStatus === PurchaseStatus.DialogProposed) {      // If not already paid, check if we could pay for it.      const res = await selectPayCoinsNew(ws, {        auditors: [], @@ -1417,7 +1418,7 @@ export async function confirmPay(        }        const oldTxState = computePayMerchantTransactionState(p);        switch (p.purchaseStatus) { -        case PurchaseStatus.Proposed: +        case PurchaseStatus.DialogProposed:            p.payInfo = {              payCoinSelection: coinSelection,              payCoinSelectionUid: encodeCrock(getRandomBytes(16)), @@ -1498,7 +1499,7 @@ export async function processPurchase(      case PurchaseStatus.FailedClaim:      case PurchaseStatus.Done:      case PurchaseStatus.RepurchaseDetected: -    case PurchaseStatus.Proposed: +    case PurchaseStatus.DialogProposed:      case PurchaseStatus.AbortedProposalRefused:      case PurchaseStatus.AbortedIncompletePayment:      case PurchaseStatus.SuspendedAbortingWithRefund: @@ -1713,7 +1714,7 @@ export async function refuseProposal(          logger.trace(`proposal ${proposalId} not found, won't refuse proposal`);          return undefined;        } -      if (proposal.purchaseStatus !== PurchaseStatus.Proposed) { +      if (proposal.purchaseStatus !== PurchaseStatus.DialogProposed) {          return undefined;        }        const oldTxState = computePayMerchantTransactionState(proposal); @@ -1791,7 +1792,7 @@ export async function abortPayMerchant(    ws.workAvailable.trigger();  } -export async function cancelAbortingPaymentTransaction( +export async function failPaymentTransaction(    ws: InternalWalletState,    proposalId: string,  ): Promise<void> { @@ -2023,7 +2024,7 @@ export function computePayMerchantTransactionState(          major: TransactionMajorState.SuspendedAborting,        };      // Dialog States -    case PurchaseStatus.Proposed: +    case PurchaseStatus.DialogProposed:        return {          major: TransactionMajorState.Dialog,          minor: TransactionMinorState.MerchantOrderProposed, @@ -2060,6 +2061,68 @@ export function computePayMerchantTransactionState(    }  } +export function computePayMerchantTransactionActions( +  purchaseRecord: PurchaseRecord, +): TransactionAction[] { +  switch (purchaseRecord.purchaseStatus) { +    // Pending States +    case PurchaseStatus.PendingDownloadingProposal: +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case PurchaseStatus.PendingPaying: +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case PurchaseStatus.PendingPayingReplay: +      // Special "abort" since it goes back to "done". +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case PurchaseStatus.PendingQueryingAutoRefund: +      // Special "abort" since it goes back to "done". +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case PurchaseStatus.PendingQueryingRefund: +      // Special "abort" since it goes back to "done". +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case PurchaseStatus.PendingAcceptRefund: +      // Special "abort" since it goes back to "done". +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    // Suspended Pending States +    case PurchaseStatus.SuspendedDownloadingProposal: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PurchaseStatus.SuspendedPaying: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PurchaseStatus.SuspendedPayingReplay: +      // Special "abort" since it goes back to "done". +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PurchaseStatus.SuspendedQueryingAutoRefund: +      // Special "abort" since it goes back to "done". +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PurchaseStatus.SuspendedQueryingRefund: +      // Special "abort" since it goes back to "done". +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PurchaseStatus.SuspendedPendingAcceptRefund: +      // Special "abort" since it goes back to "done". +      return [TransactionAction.Resume, TransactionAction.Abort]; +    // Aborting States +    case PurchaseStatus.AbortingWithRefund: +      return [TransactionAction.Fail, TransactionAction.Suspend]; +    case PurchaseStatus.SuspendedAbortingWithRefund: +      return [TransactionAction.Fail, TransactionAction.Resume]; +    // Dialog States +    case PurchaseStatus.DialogProposed: +      return []; +    // Final States +    case PurchaseStatus.AbortedProposalRefused: +      return [TransactionAction.Delete]; +    case PurchaseStatus.Done: +      return [TransactionAction.Delete]; +    case PurchaseStatus.RepurchaseDetected: +      return [TransactionAction.Delete]; +    case PurchaseStatus.AbortedIncompletePayment: +      return [TransactionAction.Delete]; +    case PurchaseStatus.FailedClaim: +      return [TransactionAction.Delete]; +    case PurchaseStatus.FailedAbort: +      return [TransactionAction.Delete]; +  } +} +  async function processPurchaseAutoRefund(    ws: InternalWalletState,    purchase: PurchaseRecord, diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts index 031bdfb92..edebad65b 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer.ts @@ -79,6 +79,7 @@ import {    TransactionMajorState,    TransactionMinorState,    TalerPreciseTimestamp, +  TransactionAction,  } from "@gnu-taler/taler-util";  import { SpendCoinDetails } from "../crypto/cryptoImplementation.js";  import { @@ -2008,7 +2009,36 @@ export function computePeerPushDebitTransactionState(      case PeerPushPaymentInitiationStatus.Failed:        return {          major: TransactionMajorState.Failed, -      } +      }; +  } +} + +export function computePeerPushDebitTransactionActions( +  ppiRecord: PeerPushPaymentInitiationRecord, +): TransactionAction[] { +  switch (ppiRecord.status) { +    case PeerPushPaymentInitiationStatus.PendingCreatePurse: +      return [TransactionAction.Abort, TransactionAction.Suspend]; +    case PeerPushPaymentInitiationStatus.PendingReady: +      return [TransactionAction.Abort, TransactionAction.Suspend]; +    case PeerPushPaymentInitiationStatus.Aborted: +      return [TransactionAction.Delete]; +    case PeerPushPaymentInitiationStatus.AbortingDeletePurse: +      return [TransactionAction.Suspend, TransactionAction.Fail]; +    case PeerPushPaymentInitiationStatus.AbortingRefresh: +      return [TransactionAction.Suspend, TransactionAction.Fail]; +    case PeerPushPaymentInitiationStatus.SuspendedAbortingDeletePurse: +      return [TransactionAction.Resume, TransactionAction.Fail]; +    case PeerPushPaymentInitiationStatus.SuspendedAbortingRefresh: +      return [TransactionAction.Resume, TransactionAction.Fail]; +    case PeerPushPaymentInitiationStatus.SuspendedCreatePurse: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PeerPushPaymentInitiationStatus.SuspendedReady: +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case PeerPushPaymentInitiationStatus.Done: +      return [TransactionAction.Delete]; +    case PeerPushPaymentInitiationStatus.Failed: +      return [TransactionAction.Delete];    }  } @@ -2072,7 +2102,7 @@ export async function abortPeerPushDebitTransaction(    notifyTransition(ws, transactionId, transitionInfo);  } -export async function cancelAbortingPeerPushDebitTransaction( +export async function failPeerPushDebitTransaction(    ws: InternalWalletState,    pursePub: string,  ) { @@ -2316,8 +2346,7 @@ export async function abortPeerPullDebitTransaction(    notifyTransition(ws, transactionId, transitionInfo);  } - -export async function cancelAbortingPeerPullDebitTransaction( +export async function failPeerPullDebitTransaction(    ws: InternalWalletState,    peerPullPaymentIncomingId: string,  ) { @@ -2501,7 +2530,6 @@ export async function suspendPeerPushCreditTransaction(    notifyTransition(ws, transactionId, transitionInfo);  } -  export async function abortPeerPushCreditTransaction(    ws: InternalWalletState,    peerPushPaymentIncomingId: string, @@ -2568,7 +2596,7 @@ export async function abortPeerPushCreditTransaction(    notifyTransition(ws, transactionId, transitionInfo);  } -export async function cancelAbortingPeerPushCreditTransaction( +export async function failPeerPushCreditTransaction(    ws: InternalWalletState,    peerPushPaymentIncomingId: string,  ) { @@ -2765,7 +2793,7 @@ export async function abortPeerPullCreditTransaction(    notifyTransition(ws, transactionId, transitionInfo);  } -export async function cancelAbortingPeerPullCreditTransaction( +export async function failPeerPullCreditTransaction(    ws: InternalWalletState,    pursePub: string,  ) { @@ -2996,12 +3024,41 @@ export function computePeerPushCreditTransactionState(        };      case PeerPushPaymentIncomingStatus.Aborted:        return { -        major: TransactionMajorState.Aborted +        major: TransactionMajorState.Aborted,        };      case PeerPushPaymentIncomingStatus.Failed:        return {          major: TransactionMajorState.Failed, -      } +      }; +    default: +      assertUnreachable(pushCreditRecord.status); +  } +} + +export function computePeerPushCreditTransactionActions( +  pushCreditRecord: PeerPushPaymentIncomingRecord, +): TransactionAction[] { +  switch (pushCreditRecord.status) { +    case PeerPushPaymentIncomingStatus.DialogProposed: +      return []; +    case PeerPushPaymentIncomingStatus.PendingMerge: +      return [TransactionAction.Abort, TransactionAction.Suspend]; +    case PeerPushPaymentIncomingStatus.Done: +      return [TransactionAction.Delete]; +    case PeerPushPaymentIncomingStatus.PendingMergeKycRequired: +      return [TransactionAction.Abort, TransactionAction.Suspend]; +    case PeerPushPaymentIncomingStatus.PendingWithdrawing: +      return [TransactionAction.Suspend, TransactionAction.Fail]; +    case PeerPushPaymentIncomingStatus.SuspendedMerge: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PeerPushPaymentIncomingStatus.SuspendedMergeKycRequired: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PeerPushPaymentIncomingStatus.SuspendedWithdrawing: +      return [TransactionAction.Resume, TransactionAction.Fail]; +    case PeerPushPaymentIncomingStatus.Aborted: +      return [TransactionAction.Delete]; +    case PeerPushPaymentIncomingStatus.Failed: +      return [TransactionAction.Delete];      default:        assertUnreachable(pushCreditRecord.status);    } @@ -3076,6 +3133,39 @@ export function computePeerPullCreditTransactionState(    }  } +export function computePeerPullCreditTransactionActions( +  pullCreditRecord: PeerPullPaymentInitiationRecord, +): TransactionAction[] { +  switch (pullCreditRecord.status) { +    case PeerPullPaymentInitiationStatus.PendingCreatePurse: +      return [TransactionAction.Abort, TransactionAction.Suspend]; +    case PeerPullPaymentInitiationStatus.PendingMergeKycRequired: +      return [TransactionAction.Abort, TransactionAction.Suspend]; +    case PeerPullPaymentInitiationStatus.PendingReady: +      return [TransactionAction.Abort, TransactionAction.Suspend]; +    case PeerPullPaymentInitiationStatus.DonePurseDeposited: +      return [TransactionAction.Delete]; +    case PeerPullPaymentInitiationStatus.PendingWithdrawing: +      return [TransactionAction.Abort, TransactionAction.Suspend]; +    case PeerPullPaymentInitiationStatus.SuspendedCreatePurse: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PeerPullPaymentInitiationStatus.SuspendedReady: +      return [TransactionAction.Abort, TransactionAction.Resume]; +    case PeerPullPaymentInitiationStatus.SuspendedWithdrawing: +      return [TransactionAction.Resume, TransactionAction.Fail]; +    case PeerPullPaymentInitiationStatus.SuspendedMergeKycRequired: +      return [TransactionAction.Resume, TransactionAction.Fail]; +    case PeerPullPaymentInitiationStatus.Aborted: +      return [TransactionAction.Delete]; +    case PeerPullPaymentInitiationStatus.AbortingDeletePurse: +      return [TransactionAction.Suspend, TransactionAction.Fail]; +    case PeerPullPaymentInitiationStatus.Failed: +      return [TransactionAction.Delete]; +    case PeerPullPaymentInitiationStatus.SuspendedAbortingDeletePurse: +      return [TransactionAction.Resume, TransactionAction.Fail]; +  } +} +  export function computePeerPullDebitTransactionState(    pullDebitRecord: PeerPullPaymentIncomingRecord,  ): TransactionState { @@ -3119,3 +3209,26 @@ export function computePeerPullDebitTransactionState(        };    }  } + +export function computePeerPullDebitTransactionActions( +  pullDebitRecord: PeerPullPaymentIncomingRecord, +): TransactionAction[] { +  switch (pullDebitRecord.status) { +    case PeerPullDebitRecordStatus.DialogProposed: +      return []; +    case PeerPullDebitRecordStatus.PendingDeposit: +      return [TransactionAction.Abort, TransactionAction.Suspend]; +    case PeerPullDebitRecordStatus.DonePaid: +      return [TransactionAction.Delete]; +    case PeerPullDebitRecordStatus.SuspendedDeposit: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case PeerPullDebitRecordStatus.Aborted: +      return [TransactionAction.Delete]; +    case PeerPullDebitRecordStatus.AbortingRefresh: +      return [TransactionAction.Fail, TransactionAction.Suspend]; +    case PeerPullDebitRecordStatus.Failed: +      return [TransactionAction.Delete]; +    case PeerPullDebitRecordStatus.SuspendedAbortingRefresh: +      return [TransactionAction.Resume, TransactionAction.Fail]; +  } +} diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts index 8437d2d0b..c2cf13857 100644 --- a/packages/taler-wallet-core/src/operations/refresh.ts +++ b/packages/taler-wallet-core/src/operations/refresh.ts @@ -50,6 +50,7 @@ import {    TalerErrorDetail,    TalerPreciseTimestamp,    TalerProtocolTimestamp, +  TransactionAction,    TransactionMajorState,    TransactionState,    TransactionType, @@ -96,7 +97,10 @@ import {    PendingTaskType,    WalletConfig,  } from "../index.js"; -import { constructTransactionIdentifier, notifyTransition } from "./transactions.js"; +import { +  constructTransactionIdentifier, +  notifyTransition, +} from "./transactions.js";  const logger = new Logger("refresh.ts"); @@ -1076,8 +1080,12 @@ export async function createRefreshGroup(   * Timestamp after which the wallet would do the next check for an auto-refresh.   */  function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime { -  const expireWithdraw = AbsoluteTime.fromProtocolTimestamp(d.stampExpireWithdraw); -  const expireDeposit = AbsoluteTime.fromProtocolTimestamp(d.stampExpireDeposit); +  const expireWithdraw = AbsoluteTime.fromProtocolTimestamp( +    d.stampExpireWithdraw, +  ); +  const expireDeposit = AbsoluteTime.fromProtocolTimestamp( +    d.stampExpireDeposit, +  );    const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit);    const deltaDiv = durationMul(delta, 0.75);    return AbsoluteTime.addDuration(expireWithdraw, deltaDiv); @@ -1087,8 +1095,12 @@ function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime {   * Timestamp after which the wallet would do an auto-refresh.   */  function getAutoRefreshExecuteThreshold(d: DenominationRecord): AbsoluteTime { -  const expireWithdraw = AbsoluteTime.fromProtocolTimestamp(d.stampExpireWithdraw); -  const expireDeposit = AbsoluteTime.fromProtocolTimestamp(d.stampExpireDeposit); +  const expireWithdraw = AbsoluteTime.fromProtocolTimestamp( +    d.stampExpireWithdraw, +  ); +  const expireDeposit = AbsoluteTime.fromProtocolTimestamp( +    d.stampExpireDeposit, +  );    const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit);    const deltaDiv = durationMul(delta, 0.5);    return AbsoluteTime.addDuration(expireWithdraw, deltaDiv); @@ -1175,7 +1187,8 @@ export async function autoRefresh(        logger.info(          `next refresh check at ${AbsoluteTime.toIsoString(minCheckThreshold)}`,        ); -      exchange.nextRefreshCheck = AbsoluteTime.toPreciseTimestamp(minCheckThreshold); +      exchange.nextRefreshCheck = +        AbsoluteTime.toPreciseTimestamp(minCheckThreshold);        await tx.exchanges.put(exchange);      });    return OperationAttemptResult.finishedEmpty(); @@ -1204,6 +1217,21 @@ export function computeRefreshTransactionState(    }  } +export function computeRefreshTransactionActions( +  rg: RefreshGroupRecord, +): TransactionAction[] { +  switch (rg.operationStatus) { +    case RefreshOperationStatus.Finished: +      return [TransactionAction.Delete]; +    case RefreshOperationStatus.Failed: +      return [TransactionAction.Delete]; +    case RefreshOperationStatus.Pending: +      return [TransactionAction.Suspend, TransactionAction.Fail]; +    case RefreshOperationStatus.Suspended: +      return [TransactionAction.Resume, TransactionAction.Fail]; +  } +} +  export async function suspendRefreshGroup(    ws: InternalWalletState,    refreshGroupId: string, @@ -1292,7 +1320,7 @@ export async function resumeRefreshGroup(    notifyTransition(ws, transactionId, transitionInfo);  } -export async function cancelAbortingRefreshGroup( +export async function failRefreshGroup(    ws: InternalWalletState,    refreshGroupId: string,  ): Promise<void> { @@ -1321,7 +1349,7 @@ export async function abortRefreshGroup(        let newStatus: RefreshOperationStatus | undefined;        switch (dg.operationStatus) {          case RefreshOperationStatus.Finished: -          break;; +          break;          case RefreshOperationStatus.Pending:          case RefreshOperationStatus.Suspended:            newStatus = RefreshOperationStatus.Failed; diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts index 0bee2b406..02c933cba 100644 --- a/packages/taler-wallet-core/src/operations/tip.ts +++ b/packages/taler-wallet-core/src/operations/tip.ts @@ -36,6 +36,7 @@ import {    TalerPreciseTimestamp,    TalerProtocolTimestamp,    TipPlanchetDetail, +  TransactionAction,    TransactionMajorState,    TransactionMinorState,    TransactionState, @@ -111,6 +112,24 @@ export function computeTipTransactionStatus(    }  } + +export function computeTipTransactionActions( +  tipRecord: TipRecord, +): TransactionAction[] { +  switch (tipRecord.status) { +    case TipRecordStatus.Done: +      return [TransactionAction.Delete]; +    case TipRecordStatus.Aborted: +      return [TransactionAction.Delete]; +    case TipRecordStatus.PendingPickup: +      return [TransactionAction.Suspend, TransactionAction.Fail]; +    case TipRecordStatus.SuspendidPickup: +      return [TransactionAction.Resume, TransactionAction.Fail]; +    default: +      assertUnreachable(tipRecord.status); +  } +} +  export async function prepareTip(    ws: InternalWalletState,    talerTipUri: string, @@ -526,7 +545,7 @@ export async function resumeTipTransaction(    notifyTransition(ws, transactionId, transitionInfo);  } -export async function cancelAbortingTipTransaction( +export async function failTipTransaction(    ws: InternalWalletState,    walletTipId: string,  ): Promise<void> { diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index d424019ac..a0da95799 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -73,32 +73,34 @@ import { constructTaskIdentifier, TaskIdentifiers } from "../util/retries.js";  import { resetOperationTimeout, TombstoneTag } from "./common.js";  import {    abortDepositGroup, -  cancelAbortingDepositGroup, +  failDepositTransaction,    computeDepositTransactionStatus,    deleteDepositGroup,    resumeDepositGroup,    suspendDepositGroup, +  computeDepositTransactionActions,  } from "./deposits.js";  import { getExchangeDetails } from "./exchanges.js";  import {    abortPayMerchant, -  cancelAbortingPaymentTransaction, +  failPaymentTransaction,    computePayMerchantTransactionState,    computeRefundTransactionState,    expectProposalDownload,    extractContractData,    resumePayMerchant,    suspendPayMerchant, +  computePayMerchantTransactionActions,  } from "./pay-merchant.js";  import {    abortPeerPullCreditTransaction,    abortPeerPullDebitTransaction,    abortPeerPushCreditTransaction,    abortPeerPushDebitTransaction, -  cancelAbortingPeerPullCreditTransaction, -  cancelAbortingPeerPullDebitTransaction, -  cancelAbortingPeerPushCreditTransaction, -  cancelAbortingPeerPushDebitTransaction, +  failPeerPullCreditTransaction, +  failPeerPullDebitTransaction, +  failPeerPushCreditTransaction, +  failPeerPushDebitTransaction,    computePeerPullCreditTransactionState,    computePeerPullDebitTransactionState,    computePeerPushCreditTransactionState, @@ -111,28 +113,35 @@ import {    suspendPeerPullDebitTransaction,    suspendPeerPushCreditTransaction,    suspendPeerPushDebitTransaction, +  computePeerPushDebitTransactionActions, +  computePeerPullDebitTransactionActions, +  computePeerPullCreditTransactionActions, +  computePeerPushCreditTransactionActions,  } from "./pay-peer.js";  import {    abortRefreshGroup, -  cancelAbortingRefreshGroup, +  failRefreshGroup,    computeRefreshTransactionState,    resumeRefreshGroup,    suspendRefreshGroup, +  computeRefreshTransactionActions,  } from "./refresh.js";  import {    abortTipTransaction, -  cancelAbortingTipTransaction, +  failTipTransaction,    computeTipTransactionStatus,    resumeTipTransaction,    suspendTipTransaction, +  computeTipTransactionActions,  } from "./tip.js";  import {    abortWithdrawalTransaction,    augmentPaytoUrisForWithdrawal, -  cancelAbortingWithdrawalTransaction, +  failWithdrawalTransaction,    computeWithdrawalTransactionStatus,    resumeWithdrawalTransaction,    suspendWithdrawalTransaction, +  computeWithdrawalTransactionActions,  } from "./withdraw.js";  const logger = new Logger("taler-wallet-core:transactions.ts"); @@ -429,6 +438,7 @@ function buildTransactionForPushPaymentDebit(    return {      type: TransactionType.PeerPushDebit,      txState: computePeerPushDebitTransactionState(pi), +    txActions: computePeerPushDebitTransactionActions(pi),      amountEffective: pi.totalCost,      amountRaw: pi.amount,      exchangeBaseUrl: pi.exchangeBaseUrl, @@ -456,6 +466,7 @@ function buildTransactionForPullPaymentDebit(    return {      type: TransactionType.PeerPullDebit,      txState: computePeerPullDebitTransactionState(pi), +    txActions: computePeerPullDebitTransactionActions(pi),      amountEffective: pi.coinSel?.totalCost        ? pi.coinSel?.totalCost        : Amounts.stringify(pi.contractTerms.amount), @@ -503,6 +514,7 @@ function buildTransactionForPeerPullCredit(      return {        type: TransactionType.PeerPullCredit,        txState: computePeerPullCreditTransactionState(pullCredit), +      txActions: computePeerPullCreditTransactionActions(pullCredit),        amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),        amountRaw: Amounts.stringify(wsr.instructedAmount),        exchangeBaseUrl: wsr.exchangeBaseUrl, @@ -533,6 +545,7 @@ function buildTransactionForPeerPullCredit(    return {      type: TransactionType.PeerPullCredit,      txState: computePeerPullCreditTransactionState(pullCredit), +    txActions: computePeerPullCreditTransactionActions(pullCredit),      amountEffective: Amounts.stringify(pullCredit.estimatedAmountEffective),      amountRaw: Amounts.stringify(peerContractTerms.amount),      exchangeBaseUrl: pullCredit.exchangeBaseUrl, @@ -569,6 +582,7 @@ function buildTransactionForPeerPushCredit(      return {        type: TransactionType.PeerPushCredit,        txState: computePeerPushCreditTransactionState(pushInc), +      txActions: computePeerPushCreditTransactionActions(pushInc),        amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),        amountRaw: Amounts.stringify(wsr.instructedAmount),        exchangeBaseUrl: wsr.exchangeBaseUrl, @@ -588,6 +602,7 @@ function buildTransactionForPeerPushCredit(    return {      type: TransactionType.PeerPushCredit,      txState: computePeerPushCreditTransactionState(pushInc), +    txActions: computePeerPushCreditTransactionActions(pushInc),      // FIXME: This is wrong, needs to consider fees!      amountEffective: Amounts.stringify(peerContractTerms.amount),      amountRaw: Amounts.stringify(peerContractTerms.amount), @@ -615,6 +630,7 @@ function buildTransactionForBankIntegratedWithdraw(    return {      type: TransactionType.Withdrawal,      txState: computeWithdrawalTransactionStatus(wgRecord), +    txActions: computeWithdrawalTransactionActions(wgRecord),      amountEffective: Amounts.stringify(wgRecord.denomsSel.totalCoinValue),      amountRaw: Amounts.stringify(wgRecord.instructedAmount),      withdrawalDetails: { @@ -656,6 +672,7 @@ function buildTransactionForManualWithdraw(    return {      type: TransactionType.Withdrawal,      txState: computeWithdrawalTransactionStatus(withdrawalGroup), +    txActions: computeWithdrawalTransactionActions(withdrawalGroup),      amountEffective: Amounts.stringify(        withdrawalGroup.denomsSel.totalCoinValue,      ), @@ -706,6 +723,7 @@ function buildTransactionForRefund(        refundGroupId: refundRecord.refundGroupId,      }),      txState: computeRefundTransactionState(refundRecord), +    txActions: [],      paymentInfo,    };  } @@ -725,6 +743,7 @@ function buildTransactionForRefresh(    return {      type: TransactionType.Refresh,      txState: computeRefreshTransactionState(refreshGroupRecord), +    txActions: computeRefreshTransactionActions(refreshGroupRecord),      refreshReason: refreshGroupRecord.reason,      amountEffective: Amounts.stringify(        Amounts.zeroOfCurrency(refreshGroupRecord.currency), @@ -759,6 +778,7 @@ function buildTransactionForDeposit(    return {      type: TransactionType.Deposit,      txState: computeDepositTransactionStatus(dg), +    txActions: computeDepositTransactionActions(dg),      amountRaw: Amounts.stringify(dg.effectiveDepositAmount),      amountEffective: Amounts.stringify(dg.totalPayCost),      timestamp: dg.timestampCreated, @@ -791,6 +811,7 @@ function buildTransactionForTip(    return {      type: TransactionType.Tip,      txState: computeTipTransactionStatus(tipRecord), +    txActions: computeTipTransactionActions(tipRecord),      amountEffective: Amounts.stringify(tipRecord.tipAmountEffective),      amountRaw: Amounts.stringify(tipRecord.tipAmountRaw),      timestamp: tipRecord.acceptedTimestamp, @@ -860,6 +881,7 @@ async function buildTransactionForPurchase(    return {      type: TransactionType.Payment,      txState: computePayMerchantTransactionState(purchaseRecord), +    txActions: computePayMerchantTransactionActions(purchaseRecord),      amountRaw: Amounts.stringify(contractData.amount),      amountEffective: Amounts.stringify(purchaseRecord.payInfo.totalPayCost),      totalRefundRaw: Amounts.stringify(zero), // FIXME! @@ -1493,7 +1515,7 @@ export async function suspendTransaction(    }  } -export async function cancelAbortingTransaction( +export async function failTransaction(    ws: InternalWalletState,    transactionId: string,  ): Promise<void> { @@ -1503,34 +1525,34 @@ export async function cancelAbortingTransaction(    }    switch (tx.tag) {      case TransactionType.Deposit: -      await cancelAbortingDepositGroup(ws, tx.depositGroupId); +      await failDepositTransaction(ws, tx.depositGroupId);        return;      case TransactionType.InternalWithdrawal:      case TransactionType.Withdrawal: -      await cancelAbortingWithdrawalTransaction(ws, tx.withdrawalGroupId); +      await failWithdrawalTransaction(ws, tx.withdrawalGroupId);        return;      case TransactionType.Payment: -      await cancelAbortingPaymentTransaction(ws, tx.proposalId); +      await failPaymentTransaction(ws, tx.proposalId);        return;      case TransactionType.Refund:        throw Error("can't do cancel-aborting on refund transaction");      case TransactionType.Tip: -      await cancelAbortingTipTransaction(ws, tx.walletTipId); +      await failTipTransaction(ws, tx.walletTipId);        return;      case TransactionType.Refresh: -      await cancelAbortingRefreshGroup(ws, tx.refreshGroupId); +      await failRefreshGroup(ws, tx.refreshGroupId);        return;      case TransactionType.PeerPullCredit: -      await cancelAbortingPeerPullCreditTransaction(ws, tx.pursePub); +      await failPeerPullCreditTransaction(ws, tx.pursePub);        return;      case TransactionType.PeerPullDebit: -      await cancelAbortingPeerPullDebitTransaction(ws, tx.peerPullPaymentIncomingId); +      await failPeerPullDebitTransaction(ws, tx.peerPullPaymentIncomingId);        return;      case TransactionType.PeerPushCredit: -      await cancelAbortingPeerPushCreditTransaction(ws, tx.peerPushPaymentIncomingId); +      await failPeerPushCreditTransaction(ws, tx.peerPushPaymentIncomingId);        return;      case TransactionType.PeerPushDebit: -      await cancelAbortingPeerPushDebitTransaction(ws, tx.pursePub); +      await failPeerPushDebitTransaction(ws, tx.pursePub);        return;      default:        assertUnreachable(tx); diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index e08aa59a7..4801a67ee 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -67,6 +67,7 @@ import {    TransactionMajorState,    TransactionMinorState,    TalerPreciseTimestamp, +  TransactionAction,  } from "@gnu-taler/taler-util";  import { EddsaKeypair } from "../crypto/cryptoImplementation.js";  import { @@ -338,7 +339,7 @@ export async function abortWithdrawalTransaction(    notifyTransition(ws, transactionId, transitionInfo);  } -export async function cancelAbortingWithdrawalTransaction( +export async function failWithdrawalTransaction(    ws: InternalWalletState,    withdrawalGroupId: string,  ) { @@ -483,6 +484,49 @@ export function computeWithdrawalTransactionStatus(    }  } +export function computeWithdrawalTransactionActions( +  wgRecord: WithdrawalGroupRecord, +): TransactionAction[] { +  switch (wgRecord.status) { +    case WithdrawalGroupStatus.FailedBankAborted: +      return [TransactionAction.Delete]; +    case WithdrawalGroupStatus.Finished: +      return [TransactionAction.Delete]; +    case WithdrawalGroupStatus.PendingRegisteringBank: +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case WithdrawalGroupStatus.PendingReady: +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case WithdrawalGroupStatus.PendingQueryingStatus: +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case WithdrawalGroupStatus.PendingWaitConfirmBank: +      return [TransactionAction.Suspend, TransactionAction.Abort]; +    case WithdrawalGroupStatus.AbortingBank: +      return [TransactionAction.Suspend, TransactionAction.Fail]; +    case WithdrawalGroupStatus.SuspendedAbortingBank: +      return [TransactionAction.Resume, TransactionAction.Fail]; +    case WithdrawalGroupStatus.SuspendedQueryingStatus: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case WithdrawalGroupStatus.SuspendedRegisteringBank: +      return [TransactionAction.Resume, TransactionAction.Abort] +    case WithdrawalGroupStatus.SuspendedWaitConfirmBank: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case WithdrawalGroupStatus.SuspendedReady: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case WithdrawalGroupStatus.PendingAml: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case WithdrawalGroupStatus.PendingKyc: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case WithdrawalGroupStatus.SuspendedAml: +      return [TransactionAction.Resume, TransactionAction.Abort]; +    case WithdrawalGroupStatus.SuspendedKyc: +      return [TransactionAction.Resume, TransactionAction.Abort] +    case WithdrawalGroupStatus.FailedAbortingBank: +      return [TransactionAction.Delete]; +    case WithdrawalGroupStatus.AbortedExchange: +      return [TransactionAction.Delete]; +  } +} +  /**   * Get information about a withdrawal from   * a taler://withdraw URI by asking the bank. diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 85b0b9250..953353164 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -232,7 +232,7 @@ import {  import { acceptTip, prepareTip, processTip } from "./operations/tip.js";  import {    abortTransaction, -  cancelAbortingTransaction, +  failTransaction,    deleteTransaction,    getTransactionById,    getTransactions, @@ -1233,7 +1233,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(      }      case WalletApiOperation.CancelAbortingTransaction: {        const req = codecForCancelAbortingTransactionRequest().decode(payload); -      await cancelAbortingTransaction(ws, req.transactionId); +      await failTransaction(ws, req.transactionId);        return {};      }      case WalletApiOperation.ResumeTransaction: { | 
