aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-10-08 23:45:49 +0200
committerFlorian Dold <florian@dold.me>2022-10-08 23:45:49 +0200
commit8ac5080607d28f8dcd84a949221a551a3f66cea8 (patch)
tree2aadd0952be1aa2dcc1cddab5de1f9218941c643
parent3897bd4f018bf23ab485325d48a259958653ff52 (diff)
wallet-core: more DB and refund fixes
-rw-r--r--packages/taler-wallet-core/src/db.ts6
-rw-r--r--packages/taler-wallet-core/src/operations/backup/export.ts16
-rw-r--r--packages/taler-wallet-core/src/operations/backup/import.ts8
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts117
-rw-r--r--packages/taler-wallet-core/src/operations/pending.ts5
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts6
6 files changed, 80 insertions, 78 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index b13428183..b019be67a 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1026,7 +1026,7 @@ export interface WalletContractData {
deliveryLocation: Location | undefined;
}
-export enum ProposalStatus {
+export enum PurchaseStatus {
/**
* Not downloaded yet.
*/
@@ -1150,7 +1150,7 @@ export interface PurchaseRecord {
*/
repurchaseProposalId: string | undefined;
- status: ProposalStatus;
+ purchaseStatus: PurchaseStatus;
/**
* Private key for the nonce.
@@ -1934,7 +1934,7 @@ export const WalletStoresV1 = {
"purchases",
describeContents<PurchaseRecord>({ keyPath: "proposalId" }),
{
- byStatus: describeIndex("byStatus", "operationStatus"),
+ byStatus: describeIndex("byStatus", "purchaseStatus"),
byFulfillmentUrl: describeIndex(
"byFulfillmentUrl",
"download.contractData.fulfillmentUrl",
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts
index 04fac7d38..d16b344f6 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -65,7 +65,7 @@ import {
CoinSourceType,
CoinStatus,
DenominationRecord,
- ProposalStatus,
+ PurchaseStatus,
RefreshCoinStatus,
RefundState,
WALLET_BACKUP_STATE_KEY,
@@ -382,21 +382,21 @@ export async function exportBackup(
}
let propStatus: BackupProposalStatus;
- switch (purch.status) {
- case ProposalStatus.Paid:
+ switch (purch.purchaseStatus) {
+ case PurchaseStatus.Paid:
propStatus = BackupProposalStatus.Paid;
return;
- case ProposalStatus.DownloadingProposal:
- case ProposalStatus.Proposed:
+ case PurchaseStatus.DownloadingProposal:
+ case PurchaseStatus.Proposed:
propStatus = BackupProposalStatus.Proposed;
break;
- case ProposalStatus.ProposalDownloadFailed:
+ case PurchaseStatus.ProposalDownloadFailed:
propStatus = BackupProposalStatus.PermanentlyFailed;
break;
- case ProposalStatus.ProposalRefused:
+ case PurchaseStatus.ProposalRefused:
propStatus = BackupProposalStatus.Refused;
break;
- case ProposalStatus.RepurchaseDetected:
+ case PurchaseStatus.RepurchaseDetected:
propStatus = BackupProposalStatus.Repurchase;
break;
default:
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts
index 00dbf6fa8..bb5fe56e2 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -46,7 +46,7 @@ import {
DenomSelectionState,
OperationStatus,
ProposalDownload,
- ProposalStatus,
+ PurchaseStatus,
PurchasePayInfo,
RefreshCoinStatus,
RefreshSessionRecord,
@@ -564,10 +564,10 @@ export async function importBackup(
const existingPurchase = await tx.purchases.get(
backupPurchase.proposal_id,
);
- let proposalStatus: ProposalStatus;
+ let proposalStatus: PurchaseStatus;
switch (backupPurchase.proposal_status) {
case BackupProposalStatus.Paid:
- proposalStatus = ProposalStatus.Paid;
+ proposalStatus = PurchaseStatus.Paid;
break;
default:
throw Error();
@@ -703,7 +703,7 @@ export async function importBackup(
payInfo,
refundAmountAwaiting: undefined,
repurchaseProposalId: backupPurchase.repurchase_proposal_id,
- status: proposalStatus,
+ purchaseStatus: proposalStatus,
timestamp: backupPurchase.timestamp_proposed,
});
}
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 97901c71e..d590177c2 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -81,7 +81,7 @@ import {
CoinStatus,
DenominationRecord,
ProposalDownload,
- ProposalStatus,
+ PurchaseStatus,
PurchaseRecord,
RefundReason,
RefundState,
@@ -230,7 +230,7 @@ async function failProposalPermanently(
if (!p) {
return;
}
- p.status = ProposalStatus.ProposalDownloadFailed;
+ p.purchaseStatus = PurchaseStatus.ProposalDownloadFailed;
await tx.purchases.put(p);
});
}
@@ -329,7 +329,7 @@ export async function processDownloadProposal(
};
}
- if (proposal.status != ProposalStatus.DownloadingProposal) {
+ if (proposal.purchaseStatus != PurchaseStatus.DownloadingProposal) {
return {
type: OperationAttemptResultType.Finished,
result: undefined,
@@ -500,7 +500,7 @@ export async function processDownloadProposal(
if (!p) {
return;
}
- if (p.status !== ProposalStatus.DownloadingProposal) {
+ if (p.purchaseStatus !== PurchaseStatus.DownloadingProposal) {
return;
}
p.download = {
@@ -516,13 +516,13 @@ export async function processDownloadProposal(
await tx.purchases.indexes.byFulfillmentUrl.get(fulfillmentUrl);
if (differentPurchase) {
logger.warn("repurchase detected");
- p.status = ProposalStatus.RepurchaseDetected;
+ p.purchaseStatus = PurchaseStatus.RepurchaseDetected;
p.repurchaseProposalId = differentPurchase.proposalId;
await tx.purchases.put(p);
return;
}
}
- p.status = ProposalStatus.Proposed;
+ p.purchaseStatus = PurchaseStatus.Proposed;
await tx.purchases.put(p);
});
@@ -595,7 +595,7 @@ async function startDownloadProposal(
merchantBaseUrl,
orderId,
proposalId: proposalId,
- status: ProposalStatus.DownloadingProposal,
+ purchaseStatus: PurchaseStatus.DownloadingProposal,
repurchaseProposalId: undefined,
downloadSessionId: sessionId,
autoRefundDeadline: undefined,
@@ -649,8 +649,8 @@ async function storeFirstPaySuccess(
logger.warn("payment success already stored");
return;
}
- if (purchase.status === ProposalStatus.Paying) {
- purchase.status = ProposalStatus.Paid;
+ if (purchase.purchaseStatus === PurchaseStatus.Paying) {
+ purchase.purchaseStatus = PurchaseStatus.Paid;
}
purchase.timestampFirstSuccessfulPay = now;
purchase.lastSessionId = sessionId;
@@ -659,7 +659,7 @@ async function storeFirstPaySuccess(
if (protoAr) {
const ar = Duration.fromTalerProtocolDuration(protoAr);
logger.info("auto_refund present");
- purchase.status = ProposalStatus.QueryingAutoRefund;
+ purchase.purchaseStatus = PurchaseStatus.QueryingAutoRefund;
purchase.autoRefundDeadline = AbsoluteTime.toTimestamp(
AbsoluteTime.addDuration(AbsoluteTime.now(), ar),
);
@@ -686,8 +686,8 @@ async function storePayReplaySuccess(
if (isFirst) {
throw Error("invalid payment state");
}
- if (purchase.status === ProposalStatus.Paying) {
- purchase.status = ProposalStatus.Paid;
+ if (purchase.purchaseStatus === PurchaseStatus.Paying) {
+ purchase.purchaseStatus = PurchaseStatus.Paid;
}
purchase.lastSessionId = sessionId;
await tx.purchases.put(purchase);
@@ -1239,7 +1239,7 @@ export async function checkPaymentByProposalId(
if (!proposal) {
throw Error(`could not get proposal ${proposalId}`);
}
- if (proposal.status === ProposalStatus.RepurchaseDetected) {
+ if (proposal.purchaseStatus === PurchaseStatus.RepurchaseDetected) {
const existingProposalId = proposal.repurchaseProposalId;
if (!existingProposalId) {
throw Error("invalid proposal state");
@@ -1274,7 +1274,7 @@ export async function checkPaymentByProposalId(
return tx.purchases.get(proposalId);
});
- if (!purchase || purchase.status === ProposalStatus.Proposed) {
+ if (!purchase || purchase.purchaseStatus === PurchaseStatus.Proposed) {
// If not already paid, check if we could pay for it.
const res = await selectPayCoinsNew(ws, {
auditors: contractData.allowedAuditors,
@@ -1315,7 +1315,7 @@ export async function checkPaymentByProposalId(
}
if (
- purchase.status === ProposalStatus.Paid &&
+ purchase.purchaseStatus === PurchaseStatus.Paid &&
purchase.lastSessionId !== sessionId
) {
logger.trace(
@@ -1330,7 +1330,7 @@ export async function checkPaymentByProposalId(
return;
}
p.lastSessionId = sessionId;
- p.status = ProposalStatus.PayingReplay;
+ p.purchaseStatus = PurchaseStatus.PayingReplay;
await tx.purchases.put(p);
});
const r = await processPurchasePay(ws, proposalId, { forceNow: true });
@@ -1361,9 +1361,9 @@ export async function checkPaymentByProposalId(
};
} else {
const paid =
- purchase.status === ProposalStatus.Paid ||
- purchase.status === ProposalStatus.QueryingRefund ||
- purchase.status === ProposalStatus.QueryingAutoRefund;
+ purchase.purchaseStatus === PurchaseStatus.Paid ||
+ purchase.purchaseStatus === PurchaseStatus.QueryingRefund ||
+ purchase.purchaseStatus === PurchaseStatus.QueryingAutoRefund;
const download = await expectProposalDownload(purchase);
return {
status: PreparePayResultType.AlreadyConfirmed,
@@ -1615,6 +1615,9 @@ export async function confirmPay(
) {
logger.trace(`changing session ID to ${sessionIdOverride}`);
purchase.lastSessionId = sessionIdOverride;
+ if (purchase.purchaseStatus === PurchaseStatus.Paid) {
+ purchase.purchaseStatus = PurchaseStatus.PayingReplay;
+ }
await tx.purchases.put(purchase);
}
return purchase;
@@ -1688,8 +1691,8 @@ export async function confirmPay(
if (!p) {
return;
}
- switch (p.status) {
- case ProposalStatus.Proposed:
+ switch (p.purchaseStatus) {
+ case PurchaseStatus.Proposed:
p.payInfo = {
payCoinSelection: coinSelection,
payCoinSelectionUid: encodeCrock(getRandomBytes(16)),
@@ -1698,7 +1701,7 @@ export async function confirmPay(
};
p.lastSessionId = sessionId;
p.timestampAccept = TalerProtocolTimestamp.now();
- p.status = ProposalStatus.Paying;
+ p.purchaseStatus = PurchaseStatus.Paying;
await tx.purchases.put(p);
await spendCoins(ws, tx, {
allocationId: `proposal:${p.proposalId}`,
@@ -1707,8 +1710,8 @@ export async function confirmPay(
refreshReason: RefreshReason.PayMerchant,
});
break;
- case ProposalStatus.Paid:
- case ProposalStatus.Paying:
+ case PurchaseStatus.Paid:
+ case PurchaseStatus.Paying:
default:
break;
}
@@ -1746,26 +1749,26 @@ export async function processPurchase(
};
}
- switch (purchase.status) {
- case ProposalStatus.DownloadingProposal:
+ switch (purchase.purchaseStatus) {
+ case PurchaseStatus.DownloadingProposal:
return processDownloadProposal(ws, proposalId, options);
- case ProposalStatus.Paying:
- case ProposalStatus.PayingReplay:
+ case PurchaseStatus.Paying:
+ case PurchaseStatus.PayingReplay:
return processPurchasePay(ws, proposalId, options);
- case ProposalStatus.QueryingAutoRefund:
- case ProposalStatus.QueryingAutoRefund:
- case ProposalStatus.AbortingWithRefund:
+ case PurchaseStatus.QueryingRefund:
+ case PurchaseStatus.QueryingAutoRefund:
+ case PurchaseStatus.AbortingWithRefund:
return processPurchaseQueryRefund(ws, proposalId, options);
- case ProposalStatus.ProposalDownloadFailed:
- case ProposalStatus.Paid:
- case ProposalStatus.AbortingWithRefund:
- case ProposalStatus.RepurchaseDetected:
+ case PurchaseStatus.ProposalDownloadFailed:
+ case PurchaseStatus.Paid:
+ case PurchaseStatus.AbortingWithRefund:
+ case PurchaseStatus.RepurchaseDetected:
return {
type: OperationAttemptResultType.Finished,
result: undefined,
};
default:
- throw Error(`unexpected purchase status (${purchase.status})`);
+ throw Error(`unexpected purchase status (${purchase.purchaseStatus})`);
}
}
@@ -1792,9 +1795,9 @@ export async function processPurchasePay(
},
};
}
- switch (purchase.status) {
- case ProposalStatus.Paying:
- case ProposalStatus.PayingReplay:
+ switch (purchase.purchaseStatus) {
+ case PurchaseStatus.Paying:
+ case PurchaseStatus.PayingReplay:
break;
default:
return OperationAttemptResult.finishedEmpty();
@@ -1870,7 +1873,7 @@ export async function processPurchasePay(
return;
}
// FIXME: Should be some "PayPermanentlyFailed" and error info should be stored
- purch.status = ProposalStatus.PaymentAbortFinished;
+ purch.purchaseStatus = PurchaseStatus.PaymentAbortFinished;
await tx.purchases.put(purch);
});
throw makePendingOperationFailedError(
@@ -1975,10 +1978,10 @@ export async function refuseProposal(
logger.trace(`proposal ${proposalId} not found, won't refuse proposal`);
return false;
}
- if (proposal.status !== ProposalStatus.Proposed) {
+ if (proposal.purchaseStatus !== PurchaseStatus.Proposed) {
return false;
}
- proposal.status = ProposalStatus.ProposalRefused;
+ proposal.purchaseStatus = PurchaseStatus.ProposalRefused;
await tx.purchases.put(proposal);
return true;
});
@@ -2211,7 +2214,7 @@ async function storeFailedRefund(
rtransactionId: r.rtransaction_id,
};
- if (p.status === ProposalStatus.AbortingWithRefund) {
+ if (p.purchaseStatus === PurchaseStatus.AbortingWithRefund) {
// Refund failed because the merchant didn't even try to deposit
// the coin yet, so we try to refresh.
if (r.exchange_code === TalerErrorCode.EXCHANGE_REFUND_DEPOSIT_NOT_FOUND) {
@@ -2346,9 +2349,9 @@ async function acceptRefunds(
if (queryDone) {
p.timestampLastRefundStatus = now;
- if (p.status === ProposalStatus.AbortingWithRefund) {
- p.status = ProposalStatus.PaymentAbortFinished;
- } else if (p.status === ProposalStatus.QueryingAutoRefund) {
+ if (p.purchaseStatus === PurchaseStatus.AbortingWithRefund) {
+ p.purchaseStatus = PurchaseStatus.PaymentAbortFinished;
+ } else if (p.purchaseStatus === PurchaseStatus.QueryingAutoRefund) {
const autoRefundDeadline = p.autoRefundDeadline;
checkDbInvariant(!!autoRefundDeadline);
if (
@@ -2356,10 +2359,10 @@ async function acceptRefunds(
AbsoluteTime.fromTimestamp(autoRefundDeadline),
)
) {
- p.status = ProposalStatus.Paid;
+ p.purchaseStatus = PurchaseStatus.Paid;
}
- } else if (p.status === ProposalStatus.QueryingRefund) {
- p.status = ProposalStatus.Paid;
+ } else if (p.purchaseStatus === PurchaseStatus.QueryingRefund) {
+ p.purchaseStatus = PurchaseStatus.Paid;
}
logger.trace("refund query done");
} else {
@@ -2483,8 +2486,8 @@ export async function applyRefundFromPurchaseId(
logger.error("no purchase found for refund URL");
return false;
}
- if (p.status === ProposalStatus.Paid) {
- p.status = ProposalStatus.QueryingRefund;
+ if (p.purchaseStatus === PurchaseStatus.Paid) {
+ p.purchaseStatus = PurchaseStatus.QueryingRefund;
}
await tx.purchases.put(p);
return true;
@@ -2610,9 +2613,9 @@ export async function processPurchaseQueryRefund(
if (
!(
- purchase.status === ProposalStatus.QueryingAutoRefund ||
- purchase.status === ProposalStatus.QueryingRefund ||
- purchase.status === ProposalStatus.AbortingWithRefund
+ purchase.purchaseStatus === PurchaseStatus.QueryingAutoRefund ||
+ purchase.purchaseStatus === PurchaseStatus.QueryingRefund ||
+ purchase.purchaseStatus === PurchaseStatus.AbortingWithRefund
)
) {
return OperationAttemptResult.finishedEmpty();
@@ -2659,7 +2662,7 @@ export async function processPurchaseQueryRefund(
refundResponse.refunds,
RefundReason.NormalRefund,
);
- } else if (purchase.status === ProposalStatus.AbortingWithRefund) {
+ } else if (purchase.purchaseStatus === PurchaseStatus.AbortingWithRefund) {
const requestUrl = new URL(
`orders/${download.contractData.orderId}/abort`,
download.contractData.merchantBaseUrl,
@@ -2745,8 +2748,8 @@ export async function abortFailedPayWithRefund(
logger.warn(`tried to abort successful payment`);
return;
}
- if (purchase.status === ProposalStatus.Paying) {
- purchase.status = ProposalStatus.AbortingWithRefund;
+ if (purchase.purchaseStatus === PurchaseStatus.Paying) {
+ purchase.purchaseStatus = PurchaseStatus.AbortingWithRefund;
}
await tx.purchases.put(purchase);
});
diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts
index db7a85432..285cef534 100644
--- a/packages/taler-wallet-core/src/operations/pending.ts
+++ b/packages/taler-wallet-core/src/operations/pending.ts
@@ -22,7 +22,7 @@
* Imports.
*/
import {
- ProposalStatus,
+ PurchaseStatus,
WalletStoresV1,
BackupProviderStateTag,
RefreshCoinStatus,
@@ -252,7 +252,6 @@ async function gatherPurchasePending(
now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
- // FIXME: Only iter purchases with some "active" flag!
const keyRange = GlobalIDB.KeyRange.bound(
OperationStatusRange.ACTIVE_START,
OperationStatusRange.ACTIVE_END,
@@ -268,7 +267,7 @@ async function gatherPurchasePending(
type: PendingTaskType.Purchase,
...getPendingCommon(ws, opId, timestampDue),
givesLifeness: true,
- statusStr: ProposalStatus[pr.status],
+ statusStr: PurchaseStatus[pr.purchaseStatus],
proposalId: pr.proposalId,
retryInfo: retryRecord?.retryInfo,
lastError: retryRecord?.lastError,
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 6ddf14f98..d8069436a 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -41,7 +41,7 @@ import {
OperationRetryRecord,
PeerPullPaymentIncomingRecord,
PeerPushPaymentInitiationRecord,
- ProposalStatus,
+ PurchaseStatus,
PurchaseRecord,
RefundState,
TipRecord,
@@ -679,7 +679,7 @@ async function buildTransactionForPurchase(
status: purchaseRecord.timestampFirstSuccessfulPay
? PaymentStatus.Paid
: PaymentStatus.Accepted,
- pending: purchaseRecord.status === ProposalStatus.Paying,
+ pending: purchaseRecord.purchaseStatus === PurchaseStatus.Paying,
refunds,
timestamp,
transactionId: makeEventId(
@@ -689,7 +689,7 @@ async function buildTransactionForPurchase(
proposalId: purchaseRecord.proposalId,
info,
frozen:
- purchaseRecord.status === ProposalStatus.PaymentAbortFinished ?? false,
+ purchaseRecord.purchaseStatus === PurchaseStatus.PaymentAbortFinished ?? false,
...(ort?.lastError ? { error: ort.lastError } : {}),
};
}