summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-05-30 09:33:32 +0200
committerFlorian Dold <florian@dold.me>2023-05-30 09:33:38 +0200
commit0323067c0757262084e16a9bba9d58bcd773fc23 (patch)
tree667a0e03825e40189b7ec9d84eb7a8b99ccad997 /packages/taler-wallet-core/src
parent246f914ca62906b463dfe98e834b5ade379a97e0 (diff)
downloadwallet-core-0323067c0757262084e16a9bba9d58bcd773fc23.tar.gz
wallet-core-0323067c0757262084e16a9bba9d58bcd773fc23.tar.bz2
wallet-core-0323067c0757262084e16a9bba9d58bcd773fc23.zip
wallet-core: add missing resume/suspend implementations
Diffstat (limited to 'packages/taler-wallet-core/src')
-rw-r--r--packages/taler-wallet-core/src/db.ts39
-rw-r--r--packages/taler-wallet-core/src/operations/backup/export.ts10
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts179
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer.ts348
-rw-r--r--packages/taler-wallet-core/src/operations/tip.ts108
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts127
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts2
7 files changed, 755 insertions, 58 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 0e35fe27c..3edaf8af5 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -863,11 +863,22 @@ export interface TipRecord {
* The url to be redirected after the tip is accepted.
*/
next_url: string | undefined;
+
/**
* Timestamp for when the wallet finished picking up the tip
* from the merchant.
*/
pickedUpTimestamp: TalerPreciseTimestamp | undefined;
+
+ status: TipRecordStatus;
+}
+
+export enum TipRecordStatus {
+ PendingPickup = 10,
+
+ SuspendidPickup = 21,
+
+ Done = 50,
}
export enum RefreshCoinStatus {
@@ -1078,12 +1089,12 @@ export enum PurchaseStatus {
/**
* Not downloaded yet.
*/
- DownloadingProposal = 10,
+ PendingDownloadingProposal = 10,
/**
* The user has accepted the proposal.
*/
- Paying = 11,
+ PendingPaying = 11,
/**
* Currently in the process of aborting with a refund.
@@ -1093,17 +1104,17 @@ export enum PurchaseStatus {
/**
* Paying a second time, likely with different session ID
*/
- PayingReplay = 13,
+ PendingPayingReplay = 13,
/**
* Query for refunds (until query succeeds).
*/
- QueryingRefund = 14,
+ PendingQueryingRefund = 14,
/**
* Query for refund (until auto-refund deadline is reached).
*/
- QueryingAutoRefund = 15,
+ PendingQueryingAutoRefund = 15,
PendingAcceptRefund = 16,
@@ -1902,7 +1913,7 @@ export interface PeerPullPaymentInitiationRecord {
export enum PeerPushPaymentIncomingStatus {
PendingMerge = 10 /* ACTIVE_START */,
- MergeKycRequired = 11 /* ACTIVE_START + 1 */,
+ PendingMergeKycRequired = 11 /* ACTIVE_START + 1 */,
/**
* Merge was successful and withdrawal group has been created, now
* everything is in the hand of the withdrawal group.
@@ -2829,6 +2840,22 @@ export const walletDbFixups: FixupDescription[] = [
});
},
},
+ {
+ name: "TipRecordRecord_status_add",
+ async fn(tx): Promise<void> {
+ await tx.tips.iter().forEachAsync(async (r) => {
+ // Remove legacy transactions that don't have the totalCost field yet.
+ if (r.status == null) {
+ if (r.pickedUpTimestamp) {
+ r.status = TipRecordStatus.Done;
+ } else {
+ r.status = TipRecordStatus.PendingPickup;
+ }
+ await tx.tips.put(r);
+ }
+ });
+ },
+ },
];
const logger = new Logger("db.ts");
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts
index ff5f1e177..0aca45551 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -412,14 +412,14 @@ export async function exportBackup(
let propStatus: BackupProposalStatus;
switch (purch.purchaseStatus) {
case PurchaseStatus.Done:
- case PurchaseStatus.QueryingAutoRefund:
- case PurchaseStatus.QueryingRefund:
+ case PurchaseStatus.PendingQueryingAutoRefund:
+ case PurchaseStatus.PendingQueryingRefund:
propStatus = BackupProposalStatus.Paid;
break;
- case PurchaseStatus.PayingReplay:
- case PurchaseStatus.DownloadingProposal:
+ case PurchaseStatus.PendingPayingReplay:
+ case PurchaseStatus.PendingDownloadingProposal:
case PurchaseStatus.Proposed:
- case PurchaseStatus.Paying:
+ case PurchaseStatus.PendingPaying:
propStatus = BackupProposalStatus.Proposed;
break;
case PurchaseStatus.FailedClaim:
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 4ea41c695..30c75f695 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -131,6 +131,7 @@ import {
import {
constructTransactionIdentifier,
notifyTransition,
+ stopLongpolling,
} from "./transactions.js";
/**
@@ -339,7 +340,7 @@ async function processDownloadProposal(
};
}
- if (proposal.purchaseStatus != PurchaseStatus.DownloadingProposal) {
+ if (proposal.purchaseStatus != PurchaseStatus.PendingDownloadingProposal) {
return {
type: OperationAttemptResultType.Finished,
result: undefined,
@@ -516,7 +517,7 @@ async function processDownloadProposal(
if (!p) {
return;
}
- if (p.purchaseStatus !== PurchaseStatus.DownloadingProposal) {
+ if (p.purchaseStatus !== PurchaseStatus.PendingDownloadingProposal) {
return;
}
const oldTxState = computePayMerchantTransactionState(p);
@@ -626,7 +627,7 @@ async function createPurchase(
merchantBaseUrl,
orderId,
proposalId: proposalId,
- purchaseStatus: PurchaseStatus.DownloadingProposal,
+ purchaseStatus: PurchaseStatus.PendingDownloadingProposal,
repurchaseProposalId: undefined,
downloadSessionId: sessionId,
autoRefundDeadline: undefined,
@@ -699,7 +700,7 @@ async function storeFirstPaySuccess(
return;
}
const oldTxState = computePayMerchantTransactionState(purchase);
- if (purchase.purchaseStatus === PurchaseStatus.Paying) {
+ if (purchase.purchaseStatus === PurchaseStatus.PendingPaying) {
purchase.purchaseStatus = PurchaseStatus.Done;
}
purchase.timestampFirstSuccessfulPay = now;
@@ -721,7 +722,7 @@ async function storeFirstPaySuccess(
if (protoAr) {
const ar = Duration.fromTalerProtocolDuration(protoAr);
logger.info("auto_refund present");
- purchase.purchaseStatus = PurchaseStatus.QueryingAutoRefund;
+ purchase.purchaseStatus = PurchaseStatus.PendingQueryingAutoRefund;
purchase.autoRefundDeadline = AbsoluteTime.toProtocolTimestamp(
AbsoluteTime.addDuration(AbsoluteTime.now(), ar),
);
@@ -760,8 +761,8 @@ async function storePayReplaySuccess(
}
const oldTxState = computePayMerchantTransactionState(purchase);
if (
- purchase.purchaseStatus === PurchaseStatus.Paying ||
- purchase.purchaseStatus === PurchaseStatus.PayingReplay
+ purchase.purchaseStatus === PurchaseStatus.PendingPaying ||
+ purchase.purchaseStatus === PurchaseStatus.PendingPayingReplay
) {
purchase.purchaseStatus = PurchaseStatus.Done;
}
@@ -1058,7 +1059,7 @@ export async function checkPaymentByProposalId(
}
const oldTxState = computePayMerchantTransactionState(p);
p.lastSessionId = sessionId;
- p.purchaseStatus = PurchaseStatus.PayingReplay;
+ p.purchaseStatus = PurchaseStatus.PendingPayingReplay;
await tx.purchases.put(p);
const newTxState = computePayMerchantTransactionState(p);
return { oldTxState, newTxState };
@@ -1098,8 +1099,8 @@ export async function checkPaymentByProposalId(
} else {
const paid =
purchase.purchaseStatus === PurchaseStatus.Done ||
- purchase.purchaseStatus === PurchaseStatus.QueryingRefund ||
- purchase.purchaseStatus === PurchaseStatus.QueryingAutoRefund;
+ purchase.purchaseStatus === PurchaseStatus.PendingQueryingRefund ||
+ purchase.purchaseStatus === PurchaseStatus.PendingQueryingAutoRefund;
const download = await expectProposalDownload(ws, purchase);
return {
status: PreparePayResultType.AlreadyConfirmed,
@@ -1348,7 +1349,7 @@ export async function confirmPay(
logger.trace(`changing session ID to ${sessionIdOverride}`);
purchase.lastSessionId = sessionIdOverride;
if (purchase.purchaseStatus === PurchaseStatus.Done) {
- purchase.purchaseStatus = PurchaseStatus.PayingReplay;
+ purchase.purchaseStatus = PurchaseStatus.PendingPayingReplay;
}
await tx.purchases.put(purchase);
}
@@ -1424,7 +1425,7 @@ export async function confirmPay(
};
p.lastSessionId = sessionId;
p.timestampAccept = TalerPreciseTimestamp.now();
- p.purchaseStatus = PurchaseStatus.Paying;
+ p.purchaseStatus = PurchaseStatus.PendingPaying;
await tx.purchases.put(p);
await spendCoins(ws, tx, {
//`txn:proposal:${p.proposalId}`
@@ -1440,7 +1441,7 @@ export async function confirmPay(
});
break;
case PurchaseStatus.Done:
- case PurchaseStatus.Paying:
+ case PurchaseStatus.PendingPaying:
default:
break;
}
@@ -1481,14 +1482,14 @@ export async function processPurchase(
}
switch (purchase.purchaseStatus) {
- case PurchaseStatus.DownloadingProposal:
+ case PurchaseStatus.PendingDownloadingProposal:
return processDownloadProposal(ws, proposalId);
- case PurchaseStatus.Paying:
- case PurchaseStatus.PayingReplay:
+ case PurchaseStatus.PendingPaying:
+ case PurchaseStatus.PendingPayingReplay:
return processPurchasePay(ws, proposalId);
- case PurchaseStatus.QueryingRefund:
+ case PurchaseStatus.PendingQueryingRefund:
return processPurchaseQueryRefund(ws, purchase);
- case PurchaseStatus.QueryingAutoRefund:
+ case PurchaseStatus.PendingQueryingAutoRefund:
return processPurchaseAutoRefund(ws, purchase);
case PurchaseStatus.AbortingWithRefund:
return processPurchaseAbortingRefund(ws, purchase);
@@ -1540,8 +1541,8 @@ export async function processPurchasePay(
};
}
switch (purchase.purchaseStatus) {
- case PurchaseStatus.Paying:
- case PurchaseStatus.PayingReplay:
+ case PurchaseStatus.PendingPaying:
+ case PurchaseStatus.PendingPayingReplay:
break;
default:
return OperationAttemptResult.finishedEmpty();
@@ -1757,11 +1758,11 @@ export async function abortPayMerchant(
logger.warn(`tried to abort successful payment`);
return;
}
- if (oldStatus === PurchaseStatus.Paying) {
+ if (oldStatus === PurchaseStatus.PendingPaying) {
purchase.purchaseStatus = PurchaseStatus.AbortingWithRefund;
}
await tx.purchases.put(purchase);
- if (oldStatus === PurchaseStatus.Paying) {
+ if (oldStatus === PurchaseStatus.PendingPaying) {
if (purchase.payInfo) {
const coinSel = purchase.payInfo.payCoinSelection;
const currency = Amounts.currencyOf(purchase.payInfo.totalPayCost);
@@ -1789,32 +1790,146 @@ export async function abortPayMerchant(
ws.workAvailable.trigger();
}
+
+const transitionSuspend: { [x in PurchaseStatus]?: {
+ next: PurchaseStatus | undefined,
+} } = {
+ [PurchaseStatus.PendingDownloadingProposal]: {
+ next: PurchaseStatus.SuspendedDownloadingProposal,
+ },
+ [PurchaseStatus.AbortingWithRefund]: {
+ next: PurchaseStatus.SuspendedAbortingWithRefund,
+ },
+ [PurchaseStatus.PendingPaying]: {
+ next: PurchaseStatus.SuspendedPaying,
+ },
+ [PurchaseStatus.PendingPayingReplay]: {
+ next: PurchaseStatus.SuspendedPayingReplay,
+ },
+ [PurchaseStatus.PendingQueryingAutoRefund]: {
+ next: PurchaseStatus.SuspendedQueryingAutoRefund,
+ }
+}
+
+const transitionResume: { [x in PurchaseStatus]?: {
+ next: PurchaseStatus | undefined,
+} } = {
+ [PurchaseStatus.SuspendedDownloadingProposal]: {
+ next: PurchaseStatus.PendingDownloadingProposal,
+ },
+ [PurchaseStatus.SuspendedAbortingWithRefund]: {
+ next: PurchaseStatus.AbortingWithRefund,
+ },
+ [PurchaseStatus.SuspendedPaying]: {
+ next: PurchaseStatus.PendingPaying,
+ },
+ [PurchaseStatus.SuspendedPayingReplay]: {
+ next: PurchaseStatus.PendingPayingReplay,
+ },
+ [PurchaseStatus.SuspendedQueryingAutoRefund]: {
+ next: PurchaseStatus.PendingQueryingAutoRefund,
+ }
+}
+
+
+export async function suspendPayMerchant(
+ ws: InternalWalletState,
+ proposalId: string,
+): Promise<void> {
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.Payment,
+ proposalId,
+ });
+ const opId = constructTaskIdentifier({
+ tag: PendingTaskType.Purchase,
+ proposalId,
+ });
+ stopLongpolling(ws, opId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [
+ x.purchases,
+ ])
+ .runReadWrite(async (tx) => {
+ const purchase = await tx.purchases.get(proposalId);
+ if (!purchase) {
+ throw Error("purchase not found");
+ }
+ const oldTxState = computePayMerchantTransactionState(purchase);
+ let newStatus = transitionSuspend[purchase.purchaseStatus];
+ if (!newStatus) {
+ return undefined;
+ }
+ await tx.purchases.put(purchase);
+ const newTxState = computePayMerchantTransactionState(purchase);
+ return { oldTxState, newTxState };
+ });
+ notifyTransition(ws, transactionId, transitionInfo);
+ ws.workAvailable.trigger();
+}
+
+
+export async function resumePayMerchant(
+ ws: InternalWalletState,
+ proposalId: string,
+): Promise<void> {
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.Payment,
+ proposalId,
+ });
+ const opId = constructTaskIdentifier({
+ tag: PendingTaskType.Purchase,
+ proposalId,
+ });
+ stopLongpolling(ws, opId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [
+ x.purchases,
+ ])
+ .runReadWrite(async (tx) => {
+ const purchase = await tx.purchases.get(proposalId);
+ if (!purchase) {
+ throw Error("purchase not found");
+ }
+ const oldTxState = computePayMerchantTransactionState(purchase);
+ let newStatus = transitionResume[purchase.purchaseStatus];
+ if (!newStatus) {
+ return undefined;
+ }
+ await tx.purchases.put(purchase);
+ const newTxState = computePayMerchantTransactionState(purchase);
+ return { oldTxState, newTxState };
+ });
+ ws.workAvailable.trigger();
+ notifyTransition(ws, transactionId, transitionInfo);
+ ws.workAvailable.trigger();
+}
+
export function computePayMerchantTransactionState(
purchaseRecord: PurchaseRecord,
): TransactionState {
switch (purchaseRecord.purchaseStatus) {
// Pending States
- case PurchaseStatus.DownloadingProposal:
+ case PurchaseStatus.PendingDownloadingProposal:
return {
major: TransactionMajorState.Pending,
minor: TransactionMinorState.ClaimProposal,
};
- case PurchaseStatus.Paying:
+ case PurchaseStatus.PendingPaying:
return {
major: TransactionMajorState.Pending,
minor: TransactionMinorState.SubmitPayment,
};
- case PurchaseStatus.PayingReplay:
+ case PurchaseStatus.PendingPayingReplay:
return {
major: TransactionMajorState.Pending,
minor: TransactionMinorState.RebindSession,
};
- case PurchaseStatus.QueryingAutoRefund:
+ case PurchaseStatus.PendingQueryingAutoRefund:
return {
major: TransactionMajorState.Pending,
minor: TransactionMinorState.AutoRefund,
};
- case PurchaseStatus.QueryingRefund:
+ case PurchaseStatus.PendingQueryingRefund:
return {
major: TransactionMajorState.Pending,
minor: TransactionMinorState.CheckRefund,
@@ -1937,7 +2052,7 @@ async function processPurchaseAutoRefund(
logger.warn("purchase does not exist anymore");
return;
}
- if (p.purchaseStatus !== PurchaseStatus.QueryingRefund) {
+ if (p.purchaseStatus !== PurchaseStatus.PendingQueryingRefund) {
return;
}
const oldTxState = computePayMerchantTransactionState(p);
@@ -1982,7 +2097,7 @@ async function processPurchaseAutoRefund(
logger.warn("purchase does not exist anymore");
return;
}
- if (p.purchaseStatus !== PurchaseStatus.QueryingAutoRefund) {
+ if (p.purchaseStatus !== PurchaseStatus.PendingQueryingAutoRefund) {
return;
}
const oldTxState = computePayMerchantTransactionState(p);
@@ -2118,7 +2233,7 @@ async function processPurchaseQueryRefund(
logger.warn("purchase does not exist anymore");
return undefined;
}
- if (p.purchaseStatus !== PurchaseStatus.QueryingRefund) {
+ if (p.purchaseStatus !== PurchaseStatus.PendingQueryingRefund) {
return undefined;
}
const oldTxState = computePayMerchantTransactionState(p);
@@ -2143,7 +2258,7 @@ async function processPurchaseQueryRefund(
logger.warn("purchase does not exist anymore");
return;
}
- if (p.purchaseStatus !== PurchaseStatus.QueryingRefund) {
+ if (p.purchaseStatus !== PurchaseStatus.PendingQueryingRefund) {
return;
}
const oldTxState = computePayMerchantTransactionState(p);
@@ -2242,7 +2357,7 @@ export async function startQueryRefund(
return;
}
const oldTxState = computePayMerchantTransactionState(p);
- p.purchaseStatus = PurchaseStatus.QueryingRefund;
+ p.purchaseStatus = PurchaseStatus.PendingQueryingRefund;
const newTxState = computePayMerchantTransactionState(p);
await tx.purchases.put(p);
return { oldTxState, newTxState };
diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts
index fb1260e3c..95878543b 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer.ts
@@ -1008,7 +1008,7 @@ export async function processPeerPushCredit(
const amount = Amounts.parseOrThrow(contractTerms.amount);
if (
- peerInc.status === PeerPushPaymentIncomingStatus.MergeKycRequired &&
+ peerInc.status === PeerPushPaymentIncomingStatus.PendingMergeKycRequired &&
peerInc.kycInfo
) {
const txId = constructTransactionIdentifier({
@@ -1080,7 +1080,7 @@ export async function processPeerPushCredit(
paytoHash: kycPending.h_payto,
requirementRow: kycPending.requirement_row,
};
- peerInc.status = PeerPushPaymentIncomingStatus.MergeKycRequired;
+ peerInc.status = PeerPushPaymentIncomingStatus.PendingMergeKycRequired;
await tx.peerPushPaymentIncoming.put(peerInc);
});
return {
@@ -1122,7 +1122,7 @@ export async function processPeerPushCredit(
}
if (
peerInc.status === PeerPushPaymentIncomingStatus.PendingMerge ||
- peerInc.status === PeerPushPaymentIncomingStatus.MergeKycRequired
+ peerInc.status === PeerPushPaymentIncomingStatus.PendingMergeKycRequired
) {
peerInc.status = PeerPushPaymentIncomingStatus.Done;
}
@@ -2186,6 +2186,345 @@ export async function suspendPeerPushDebitTransaction(
notifyTransition(ws, transactionId, transitionInfo);
}
+export async function suspendPeerPullDebitTransaction(
+ ws: InternalWalletState,
+ peerPullPaymentIncomingId: string,
+) {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPullDebit,
+ peerPullPaymentIncomingId,
+ });
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPullDebit,
+ peerPullPaymentIncomingId,
+ });
+ stopLongpolling(ws, taskId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.peerPullPaymentIncoming])
+ .runReadWrite(async (tx) => {
+ const pullDebitRec = await tx.peerPullPaymentIncoming.get(
+ peerPullPaymentIncomingId,
+ );
+ if (!pullDebitRec) {
+ logger.warn(`peer pull debit ${peerPullPaymentIncomingId} not found`);
+ return;
+ }
+ let newStatus: PeerPullDebitRecordStatus | undefined = undefined;
+ switch (pullDebitRec.status) {
+ case PeerPullDebitRecordStatus.DialogProposed:
+ break;
+ case PeerPullDebitRecordStatus.DonePaid:
+ break;
+ case PeerPullDebitRecordStatus.PendingDeposit:
+ newStatus = PeerPullDebitRecordStatus.SuspendedDeposit;
+ break;
+ case PeerPullDebitRecordStatus.SuspendedDeposit:
+ break;
+ default:
+ assertUnreachable(pullDebitRec.status);
+ }
+ if (newStatus != null) {
+ const oldTxState = computePeerPullDebitTransactionState(pullDebitRec);
+ pullDebitRec.status = newStatus;
+ const newTxState = computePeerPullDebitTransactionState(pullDebitRec);
+ await tx.peerPullPaymentIncoming.put(pullDebitRec);
+ return {
+ oldTxState,
+ newTxState,
+ };
+ }
+ return undefined;
+ });
+ notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function resumePeerPullDebitTransaction(
+ ws: InternalWalletState,
+ peerPullPaymentIncomingId: string,
+) {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPullDebit,
+ peerPullPaymentIncomingId,
+ });
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPullDebit,
+ peerPullPaymentIncomingId,
+ });
+ stopLongpolling(ws, taskId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.peerPullPaymentIncoming])
+ .runReadWrite(async (tx) => {
+ const pullDebitRec = await tx.peerPullPaymentIncoming.get(
+ peerPullPaymentIncomingId,
+ );
+ if (!pullDebitRec) {
+ logger.warn(`peer pull debit ${peerPullPaymentIncomingId} not found`);
+ return;
+ }
+ let newStatus: PeerPullDebitRecordStatus | undefined = undefined;
+ switch (pullDebitRec.status) {
+ case PeerPullDebitRecordStatus.DialogProposed:
+ case PeerPullDebitRecordStatus.DonePaid:
+ case PeerPullDebitRecordStatus.PendingDeposit:
+ break;
+ case PeerPullDebitRecordStatus.SuspendedDeposit:
+ newStatus = PeerPullDebitRecordStatus.PendingDeposit;
+ break;
+ default:
+ assertUnreachable(pullDebitRec.status);
+ }
+ if (newStatus != null) {
+ const oldTxState = computePeerPullDebitTransactionState(pullDebitRec);
+ pullDebitRec.status = newStatus;
+ const newTxState = computePeerPullDebitTransactionState(pullDebitRec);
+ await tx.peerPullPaymentIncoming.put(pullDebitRec);
+ return {
+ oldTxState,
+ newTxState,
+ };
+ }
+ return undefined;
+ });
+ ws.workAvailable.trigger();
+ notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function suspendPeerPushCreditTransaction(
+ ws: InternalWalletState,
+ peerPushPaymentIncomingId: string,
+) {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPushCredit,
+ peerPushPaymentIncomingId,
+ });
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPushCredit,
+ peerPushPaymentIncomingId,
+ });
+ stopLongpolling(ws, taskId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.peerPushPaymentIncoming])
+ .runReadWrite(async (tx) => {
+ const pushCreditRec = await tx.peerPushPaymentIncoming.get(
+ peerPushPaymentIncomingId,
+ );
+ if (!pushCreditRec) {
+ logger.warn(`peer push credit ${peerPushPaymentIncomingId} not found`);
+ return;
+ }
+ let newStatus: PeerPushPaymentIncomingStatus | undefined = undefined;
+ switch (pushCreditRec.status) {
+ case PeerPushPaymentIncomingStatus.DialogProposed:
+ case PeerPushPaymentIncomingStatus.Done:
+ case PeerPushPaymentIncomingStatus.SuspendedMerge:
+ case PeerPushPaymentIncomingStatus.SuspendedMergeKycRequired:
+ case PeerPushPaymentIncomingStatus.SuspendedWithdrawing:
+ break;
+ case PeerPushPaymentIncomingStatus.PendingMergeKycRequired:
+ newStatus = PeerPushPaymentIncomingStatus.SuspendedMergeKycRequired;
+ break;
+ case PeerPushPaymentIncomingStatus.PendingMerge:
+ newStatus = PeerPushPaymentIncomingStatus.SuspendedMerge;
+ break;
+ case PeerPushPaymentIncomingStatus.PendingWithdrawing:
+ // FIXME: Suspend internal withdrawal transaction!
+ newStatus = PeerPushPaymentIncomingStatus.SuspendedWithdrawing;
+ break;
+ default:
+ assertUnreachable(pushCreditRec.status);
+ }
+ if (newStatus != null) {
+ const oldTxState = computePeerPushCreditTransactionState(pushCreditRec);
+ pushCreditRec.status = newStatus;
+ const newTxState = computePeerPushCreditTransactionState(pushCreditRec);
+ await tx.peerPushPaymentIncoming.put(pushCreditRec);
+ return {
+ oldTxState,
+ newTxState,
+ };
+ }
+ return undefined;
+ });
+ notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function resumePeerPushCreditTransaction(
+ ws: InternalWalletState,
+ peerPushPaymentIncomingId: string,
+) {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPushCredit,
+ peerPushPaymentIncomingId,
+ });
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPushCredit,
+ peerPushPaymentIncomingId,
+ });
+ stopLongpolling(ws, taskId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.peerPushPaymentIncoming])
+ .runReadWrite(async (tx) => {
+ const pushCreditRec = await tx.peerPushPaymentIncoming.get(
+ peerPushPaymentIncomingId,
+ );
+ if (!pushCreditRec) {
+ logger.warn(`peer push credit ${peerPushPaymentIncomingId} not found`);
+ return;
+ }
+ let newStatus: PeerPushPaymentIncomingStatus | undefined = undefined;
+ switch (pushCreditRec.status) {
+ case PeerPushPaymentIncomingStatus.DialogProposed:
+ case PeerPushPaymentIncomingStatus.Done:
+ case PeerPushPaymentIncomingStatus.PendingMergeKycRequired:
+ case PeerPushPaymentIncomingStatus.PendingMerge:
+ case PeerPushPaymentIncomingStatus.PendingWithdrawing:
+ case PeerPushPaymentIncomingStatus.SuspendedMerge:
+ newStatus = PeerPushPaymentIncomingStatus.PendingMerge;
+ break;
+ case PeerPushPaymentIncomingStatus.SuspendedMergeKycRequired:
+ newStatus = PeerPushPaymentIncomingStatus.PendingMergeKycRequired;
+ break;
+ case PeerPushPaymentIncomingStatus.SuspendedWithdrawing:
+ // FIXME: resume underlying "internal-withdrawal" transaction.
+ newStatus = PeerPushPaymentIncomingStatus.PendingWithdrawing;
+ break;
+ default:
+ assertUnreachable(pushCreditRec.status);
+ }
+ if (newStatus != null) {
+ const oldTxState = computePeerPushCreditTransactionState(pushCreditRec);
+ pushCreditRec.status = newStatus;
+ const newTxState = computePeerPushCreditTransactionState(pushCreditRec);
+ await tx.peerPushPaymentIncoming.put(pushCreditRec);
+ return {
+ oldTxState,
+ newTxState,
+ };
+ }
+ return undefined;
+ });
+ ws.workAvailable.trigger();
+ notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function suspendPeerPullCreditTransaction(
+ ws: InternalWalletState,
+ pursePub: string,
+) {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPullCredit,
+ pursePub,
+ });
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPullCredit,
+ pursePub,
+ });
+ stopLongpolling(ws, taskId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.peerPullPaymentInitiations])
+ .runReadWrite(async (tx) => {
+ const pullCreditRec = await tx.peerPullPaymentInitiations.get(pursePub);
+ if (!pullCreditRec) {
+ logger.warn(`peer pull credit ${pursePub} not found`);
+ return;
+ }
+ let newStatus: PeerPullPaymentInitiationStatus | undefined = undefined;
+ switch (pullCreditRec.status) {
+ case PeerPullPaymentInitiationStatus.PendingCreatePurse:
+ newStatus = PeerPullPaymentInitiationStatus.SuspendedCreatePurse;
+ break;
+ case PeerPullPaymentInitiationStatus.PendingMergeKycRequired:
+ newStatus = PeerPullPaymentInitiationStatus.SuspendedMergeKycRequired;
+ break;
+ case PeerPullPaymentInitiationStatus.PendingWithdrawing:
+ newStatus = PeerPullPaymentInitiationStatus.SuspendedWithdrawing;
+ break;
+ case PeerPullPaymentInitiationStatus.PendingReady:
+ newStatus = PeerPullPaymentInitiationStatus.SuspendedReady;
+ break;
+ case PeerPullPaymentInitiationStatus.DonePurseDeposited:
+ case PeerPullPaymentInitiationStatus.SuspendedCreatePurse:
+ case PeerPullPaymentInitiationStatus.SuspendedMergeKycRequired:
+ case PeerPullPaymentInitiationStatus.SuspendedReady:
+ case PeerPullPaymentInitiationStatus.SuspendedWithdrawing:
+ break;
+ default:
+ assertUnreachable(pullCreditRec.status);
+ }
+ if (newStatus != null) {
+ const oldTxState = computePeerPullCreditTransactionState(pullCreditRec);
+ pullCreditRec.status = newStatus;
+ const newTxState = computePeerPullCreditTransactionState(pullCreditRec);
+ await tx.peerPullPaymentInitiations.put(pullCreditRec);
+ return {
+ oldTxState,
+ newTxState,
+ };
+ }
+ return undefined;
+ });
+ notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function resumePeerPullCreditTransaction(
+ ws: InternalWalletState,
+ pursePub: string,
+) {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPullCredit,
+ pursePub,
+ });
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPullCredit,
+ pursePub,
+ });
+ stopLongpolling(ws, taskId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.peerPullPaymentInitiations])
+ .runReadWrite(async (tx) => {
+ const pullCreditRec = await tx.peerPullPaymentInitiations.get(pursePub);
+ if (!pullCreditRec) {
+ logger.warn(`peer pull credit ${pursePub} not found`);
+ return;
+ }
+ let newStatus: PeerPullPaymentInitiationStatus | undefined = undefined;
+ switch (pullCreditRec.status) {
+ case PeerPullPaymentInitiationStatus.PendingCreatePurse:
+ case PeerPullPaymentInitiationStatus.PendingMergeKycRequired:
+ case PeerPullPaymentInitiationStatus.PendingWithdrawing:
+ case PeerPullPaymentInitiationStatus.PendingReady:
+ case PeerPullPaymentInitiationStatus.DonePurseDeposited:
+ case PeerPullPaymentInitiationStatus.SuspendedCreatePurse:
+ newStatus = PeerPullPaymentInitiationStatus.PendingCreatePurse;
+ break;
+ case PeerPullPaymentInitiationStatus.SuspendedMergeKycRequired:
+ newStatus = PeerPullPaymentInitiationStatus.PendingMergeKycRequired;
+ break;
+ case PeerPullPaymentInitiationStatus.SuspendedReady:
+ newStatus = PeerPullPaymentInitiationStatus.PendingReady;
+ break;
+ case PeerPullPaymentInitiationStatus.SuspendedWithdrawing:
+ newStatus = PeerPullPaymentInitiationStatus.PendingWithdrawing;
+ break;
+ default:
+ assertUnreachable(pullCreditRec.status);
+ }
+ if (newStatus != null) {
+ const oldTxState = computePeerPullCreditTransactionState(pullCreditRec);
+ pullCreditRec.status = newStatus;
+ const newTxState = computePeerPullCreditTransactionState(pullCreditRec);
+ await tx.peerPullPaymentInitiations.put(pullCreditRec);
+ return {
+ oldTxState,
+ newTxState,
+ };
+ }
+ return undefined;
+ });
+ ws.workAvailable.trigger();
+ notifyTransition(ws, transactionId, transitionInfo);
+}
+
export async function resumePeerPushDebitTransaction(
ws: InternalWalletState,
pursePub: string,
@@ -2244,6 +2583,7 @@ export async function resumePeerPushDebitTransaction(
}
return undefined;
});
+ ws.workAvailable.trigger();
notifyTransition(ws, transactionId, transitionInfo);
}
@@ -2265,7 +2605,7 @@ export function computePeerPushCreditTransactionState(
return {
major: TransactionMajorState.Done,
};
- case PeerPushPaymentIncomingStatus.MergeKycRequired:
+ case PeerPushPaymentIncomingStatus.PendingMergeKycRequired:
return {
major: TransactionMajorState.Pending,
minor: TransactionMinorState.KycRequired,
diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts
index 524970faa..70b595c2f 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -48,6 +48,7 @@ import {
CoinSourceType,
DenominationRecord,
TipRecord,
+ TipRecordStatus,
} from "../db.js";
import { makeErrorDetail } from "@gnu-taler/taler-util";
import { InternalWalletState } from "../internal-wallet-state.js";
@@ -57,6 +58,7 @@ import {
} from "@gnu-taler/taler-util/http";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import {
+ constructTaskIdentifier,
OperationAttemptResult,
OperationAttemptResultType,
} from "../util/retries.js";
@@ -68,7 +70,13 @@ import {
updateWithdrawalDenoms,
} from "./withdraw.js";
import { selectWithdrawalDenominations } from "../util/coinSelection.js";
-import { constructTransactionIdentifier } from "./transactions.js";
+import {
+ constructTransactionIdentifier,
+ notifyTransition,
+ stopLongpolling,
+} from "./transactions.js";
+import { PendingTaskType } from "../pending-types.js";
+import { assertUnreachable } from "../util/assertUnreachable.js";
const logger = new Logger("operations/tip.ts");
@@ -156,6 +164,7 @@ export async function prepareTip(
const newTipRecord: TipRecord = {
walletTipId: walletTipId,
acceptedTimestamp: undefined,
+ status: TipRecordStatus.PendingPickup,
tipAmountRaw: Amounts.stringify(amount),
tipExpiration: tipPickupStatus.expiration,
exchangeBaseUrl: tipPickupStatus.exchange_url,
@@ -180,7 +189,7 @@ export async function prepareTip(
const transactionId = constructTransactionIdentifier({
tag: TransactionType.Tip,
walletTipId: tipRecord.walletTipId,
- })
+ });
const tipStatus: PrepareTipResult = {
accepted: !!tipRecord && !!tipRecord.acceptedTimestamp,
@@ -410,3 +419,98 @@ export async function acceptTip(
next_url: found?.next_url,
};
}
+
+export async function suspendTipTransaction(
+ ws: InternalWalletState,
+ walletTipId: string,
+): Promise<void> {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.TipPickup,
+ walletTipId,
+ });
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.Tip,
+ walletTipId,
+ });
+ stopLongpolling(ws, taskId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.tips])
+ .runReadWrite(async (tx) => {
+ const tipRec = await tx.tips.get(walletTipId);
+ if (!tipRec) {
+ logger.warn(`transaction tip ${walletTipId} not found`);
+ return;
+ }
+ let newStatus: TipRecordStatus | undefined = undefined;
+ switch (tipRec.status) {
+ case TipRecordStatus.Done:
+ case TipRecordStatus.SuspendidPickup:
+ break;
+ case TipRecordStatus.PendingPickup:
+ newStatus = TipRecordStatus.SuspendidPickup;
+ break;
+ default:
+ assertUnreachable(tipRec.status);
+ }
+ if (newStatus != null) {
+ const oldTxState = computeTipTransactionStatus(tipRec);
+ tipRec.status = newStatus;
+ const newTxState = computeTipTransactionStatus(tipRec);
+ await tx.tips.put(tipRec);
+ return {
+ oldTxState,
+ newTxState,
+ };
+ }
+ return undefined;
+ });
+ ws.workAvailable.trigger();
+ notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function resumeTipTransaction(
+ ws: InternalWalletState,
+ walletTipId: string,
+): Promise<void> {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.TipPickup,
+ walletTipId,
+ });
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.Tip,
+ walletTipId,
+ });
+ stopLongpolling(ws, taskId);
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.tips])
+ .runReadWrite(async (tx) => {
+ const tipRec = await tx.tips.get(walletTipId);
+ if (!tipRec) {
+ logger.warn(`transaction tip ${walletTipId} not found`);
+ return;
+ }
+ let newStatus: TipRecordStatus | undefined = undefined;
+ switch (tipRec.status) {
+ case TipRecordStatus.Done:
+ case TipRecordStatus.SuspendidPickup:
+ newStatus = TipRecordStatus.PendingPickup;
+ break;
+ case TipRecordStatus.PendingPickup:
+ break;
+ default:
+ assertUnreachable(tipRec.status);
+ }
+ if (newStatus != null) {
+ const oldTxState = computeTipTransactionStatus(tipRec);
+ tipRec.status = newStatus;
+ const newTxState = computeTipTransactionStatus(tipRec);
+ await tx.tips.put(tipRec);
+ return {
+ oldTxState,
+ newTxState,
+ };
+ }
+ return undefined;
+ });
+ notifyTransition(ws, transactionId, transitionInfo);
+}
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 3645edd93..f1cfaed45 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -86,20 +86,40 @@ import {
computeRefundTransactionState,
expectProposalDownload,
extractContractData,
+ resumePayMerchant,
+ suspendPayMerchant,
} from "./pay-merchant.js";
import {
computePeerPullCreditTransactionState,
computePeerPullDebitTransactionState,
computePeerPushCreditTransactionState,
computePeerPushDebitTransactionState,
+ resumePeerPullCreditTransaction,
+ resumePeerPullDebitTransaction,
+ resumePeerPushCreditTransaction,
+ resumePeerPushDebitTransaction,
+ suspendPeerPullCreditTransaction,
+ suspendPeerPullDebitTransaction,
+ suspendPeerPushCreditTransaction,
+ suspendPeerPushDebitTransaction,
} from "./pay-peer.js";
-import { computeRefreshTransactionState } from "./refresh.js";
-import { computeTipTransactionStatus } from "./tip.js";
+import {
+ computeRefreshTransactionState,
+ resumeRefreshGroup,
+ suspendRefreshGroup,
+} from "./refresh.js";
+import {
+ computeTipTransactionStatus,
+ resumeTipTransaction,
+ suspendTipTransaction,
+} from "./tip.js";
import {
abortWithdrawalTransaction,
augmentPaytoUrisForWithdrawal,
cancelAbortingWithdrawalTransaction,
computeWithdrawalTransactionStatus,
+ resumeWithdrawalTransaction,
+ suspendWithdrawalTransaction,
} from "./withdraw.js";
const logger = new Logger("taler-wallet-core:transactions.ts");
@@ -159,6 +179,7 @@ export async function getTransactionById(
}
switch (parsedTx.tag) {
+ case TransactionType.InternalWithdrawal:
case TransactionType.Withdrawal: {
const withdrawalGroupId = parsedTx.withdrawalGroupId;
return await ws.db
@@ -844,7 +865,7 @@ async function buildTransactionForPurchase(
proposalId: purchaseRecord.proposalId,
info,
refundQueryActive:
- purchaseRecord.purchaseStatus === PurchaseStatus.QueryingRefund,
+ purchaseRecord.purchaseStatus === PurchaseStatus.PendingQueryingRefund,
...(ort?.lastError ? { error: ort.lastError } : {}),
};
}
@@ -1197,7 +1218,8 @@ export type ParsedTransactionIdentifier =
| { tag: TransactionType.Refresh; refreshGroupId: string }
| { tag: TransactionType.Refund; refundGroupId: string }
| { tag: TransactionType.Tip; walletTipId: string }
- | { tag: TransactionType.Withdrawal; withdrawalGroupId: string };
+ | { tag: TransactionType.Withdrawal; withdrawalGroupId: string }
+ | { tag: TransactionType.InternalWithdrawal; withdrawalGroupId: string };
export function constructTransactionIdentifier(
pTxId: ParsedTransactionIdentifier,
@@ -1223,6 +1245,8 @@ export function constructTransactionIdentifier(
return `txn:${pTxId.tag}:${pTxId.walletTipId}` as TransactionIdStr;
case TransactionType.Withdrawal:
return `txn:${pTxId.tag}:${pTxId.withdrawalGroupId}` as TransactionIdStr;
+ case TransactionType.InternalWithdrawal:
+ return `txn:${pTxId.tag}:${pTxId.withdrawalGroupId}` as TransactionIdStr;
default:
assertUnreachable(pTxId);
}
@@ -1242,6 +1266,10 @@ export function parseTransactionIdentifier(
const [prefix, type, ...rest] = txnParts;
+ if (prefix != "txn") {
+ throw Error("invalid transaction identifier");
+ }
+
switch (type) {
case TransactionType.Deposit:
return { tag: TransactionType.Deposit, depositGroupId: rest[0] };
@@ -1329,6 +1357,7 @@ export async function retryTransaction(
stopLongpolling(ws, taskId);
break;
}
+ case TransactionType.InternalWithdrawal:
case TransactionType.Withdrawal: {
// FIXME: Abort current long-poller!
const taskId = constructTaskIdentifier({
@@ -1366,8 +1395,38 @@ export async function retryTransaction(
stopLongpolling(ws, taskId);
break;
}
- default:
+ case TransactionType.PeerPullDebit: {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPullDebit,
+ peerPullPaymentIncomingId: parsedTx.peerPullPaymentIncomingId,
+ });
+ await resetOperationTimeout(ws, taskId);
+ stopLongpolling(ws, taskId);
+ break;
+ }
+ case TransactionType.PeerPushCredit: {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPushCredit,
+ peerPushPaymentIncomingId: parsedTx.peerPushPaymentIncomingId,
+ });
+ await resetOperationTimeout(ws, taskId);
+ stopLongpolling(ws, taskId);
break;
+ }
+ case TransactionType.PeerPushDebit: {
+ const taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPushDebit,
+ pursePub: parsedTx.pursePub,
+ });
+ await resetOperationTimeout(ws, taskId);
+ stopLongpolling(ws, taskId);
+ break;
+ }
+ case TransactionType.Refund:
+ // Nothing to do for a refund transaction.
+ break;
+ default:
+ assertUnreachable(parsedTx);
}
}
@@ -1389,8 +1448,35 @@ export async function suspendTransaction(
case TransactionType.Deposit:
await suspendDepositGroup(ws, tx.depositGroupId);
return;
+ case TransactionType.Refresh:
+ await suspendRefreshGroup(ws, tx.refreshGroupId);
+ return;
+ case TransactionType.InternalWithdrawal:
+ case TransactionType.Withdrawal:
+ await suspendWithdrawalTransaction(ws, tx.withdrawalGroupId);
+ return;
+ case TransactionType.Payment:
+ await suspendPayMerchant(ws, tx.proposalId);
+ return;
+ case TransactionType.PeerPullCredit:
+ await suspendPeerPullCreditTransaction(ws, tx.pursePub);
+ break;
+ case TransactionType.PeerPushDebit:
+ await suspendPeerPushDebitTransaction(ws, tx.pursePub);
+ break;
+ case TransactionType.PeerPullDebit:
+ await suspendPeerPullDebitTransaction(ws, tx.peerPullPaymentIncomingId);
+ break;
+ case TransactionType.PeerPushCredit:
+ await suspendPeerPushCreditTransaction(ws, tx.peerPushPaymentIncomingId);
+ break;
+ case TransactionType.Refund:
+ throw Error("refund transactions can't be suspended or resumed");
+ case TransactionType.Tip:
+ await suspendTipTransaction(ws, tx.walletTipId);
+ break;
default:
- logger.warn(`unable to suspend transaction of type '${tx.tag}'`);
+ assertUnreachable(tx);
}
}
@@ -1429,8 +1515,33 @@ export async function resumeTransaction(
case TransactionType.Deposit:
await resumeDepositGroup(ws, tx.depositGroupId);
return;
- default:
- logger.warn(`unable to resume transaction of type '${tx.tag}'`);
+ case TransactionType.Refresh:
+ await resumeRefreshGroup(ws, tx.refreshGroupId);
+ return;
+ case TransactionType.InternalWithdrawal:
+ case TransactionType.Withdrawal:
+ await resumeWithdrawalTransaction(ws, tx.withdrawalGroupId);
+ return;
+ case TransactionType.Payment:
+ await resumePayMerchant(ws, tx.proposalId);
+ return;
+ case TransactionType.PeerPullCredit:
+ await resumePeerPullCreditTransaction(ws, tx.pursePub);
+ break;
+ case TransactionType.PeerPushDebit:
+ await resumePeerPushDebitTransaction(ws, tx.pursePub);
+ break;
+ case TransactionType.PeerPullDebit:
+ await resumePeerPullDebitTransaction(ws, tx.peerPullPaymentIncomingId);
+ break;
+ case TransactionType.PeerPushCredit:
+ await resumePeerPushCreditTransaction(ws, tx.peerPushPaymentIncomingId);
+ break;
+ case TransactionType.Refund:
+ throw Error("refund transactions can't be suspended or resumed");
+ case TransactionType.Tip:
+ await resumeTipTransaction(ws, tx.walletTipId);
+ break;
}
}
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index ae170fa2c..7636395bd 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -259,7 +259,7 @@ export async function resumeWithdrawalTransaction(
}
return undefined;
});
-
+ ws.workAvailable.trigger();
const transactionId = constructTransactionIdentifier({
tag: TransactionType.Withdrawal,
withdrawalGroupId,